Ext.form.Field.prototype.msgTarget = 'side';
Array.prototype.unique = function() {
    var o = {}, i, l = this.length, r = [];
    for(i=0; i<l;i+=1) o[this[i]] = this[i];
    for(i in o) r.push(o[i]);
    return r;
};

//做一个开始的域名空间
Ext.ns('ZM');

/*console.log fixed*/
if(!window.console) {
    window.console = {};
    window.console.log = function(){};
}

ZM.diffDay = function(d){
    function _tsb(dd){
        return dd.getFullYear()+'-'+dd.getMonth()+'-'+dd.getDate()
    };
    var a = new Date(),a1 = new Date(),a2 = new Date(), b = new Date(d.replace(/-/g,'/'));
    a1.setDate(a.getDate() - 1);
    a2.setDate(a.getDate() - 2);
    

    if(_tsb(a)==_tsb(b)){
        return '<span style="color:red">'+b.getHours()+':'+b.getMinutes()+'</span>';
    }else if(_tsb(a1)==_tsb(b)){
        return '昨天'+b.getHours()+':'+b.getMinutes();
    }else if(_tsb(a2)==_tsb(b)){
        return '前天'+b.getHours()+':'+b.getMinutes();
    }
    return d;
}

ZM.btn = function() {
    var id = arguments[2].id;
    var str = '';
    Ext.each(this.btns, function(item) {
        str += String.format('<a id="_{0}" title="{1}" href="#">[{2}]</a>', id,
                item.fn, item.text)
    })
    return str;
}



/**
 * failure success
 * 
 * @params 参数
 * @url 进行action处理的链接
 */
ZM.ajax = function(config) {
    config = Ext.apply({
        url: '',
        success: Ext.emptyFn,
        failure: Ext.emptyFn,
        params: {},
        crossDomain: false
    },config);
    this._handler = function(response) {
        var responseInfo = (this.crossDomain) ? response : Ext.decode(response.responseText);
        if(this.mask) {
            this.mask.unmask();
        }
        if (responseInfo.success === true) {
            this.success(responseInfo);
        } else {
            Ext.Msg.alert(Ext.langs.error, responseInfo.detail, function() {
                if (responseInfo.addon && responseInfo.addon.fatal) {
                    location.reload();
                } else {
                    this.failure(responseInfo)
                }
            },this);
        }
    }
    
    if(config.mask) {
        if(config.mask.getXType) {
            config.mask = config.mask.getEl();
        }
        config.mask.mask(Ext.langs.processing,'x-mask-loading');
    }
    return Ext.Ajax.request(Ext.applyIf({
        url :config.url,
        success :this._handler.createDelegate(config),
        failure : function() {
            Ext.MessageBox.show( {
                title :Ext.langs.error,
                msg :Ext.langs.connectErrorMsg,
                buttons :Ext.MessageBox.OK,
                icon :Ext.MessageBox.ERROR
            });
        },
        params :config.params
    },config));
};

ZM.getDataIndex = function(config) {
    if (!config.grid || !config.dataIndex)
        return '';
    var SelectionModel = config.grid.getSelectionModel();
    var selections = SelectionModel.selections;
    var tempArr = [];
    Ext.each(selections.items, function(item) {
        tempArr.push(item.data[config.dataIndex]);
    })
    return tempArr;
}
/**
 * 对grid选中项进行批量处理
 * 
 * @grid 进行处理的grid对像
 * @postName POST给后台的对像名
 * @dataIndex 需要提交的dateIndex列
 * @url 进行action处理的链接
 */
ZM.sbGrid = function(config) {

    var SelectionModel = config.grid.getSelectionModel();
    var selections = SelectionModel.selections;
    var docStore = config.grid.store;
    var success = config.success || function() {
        docStore.reload()
    };

    var tempArr = [];
    var params = config.params || {};

    if (selections.length < 1) {
        Ext.MessageBox.alert(Ext.langs.tip, Ext.langs.noItemSeleced);
        return;
    }
    ;
    Ext.Msg.confirm(Ext.langs.confirm, config.detail || Ext.langs.confirmDoAction, function(btn) {
        if (btn == 'yes') {
            // ///
            Ext.each(selections.items, function(item) {
                tempArr.push(item.data[config.dataIndex]);
            })

            config.grid.getEl().mask(Ext.langs.processing, 'x-mask-loading');
            params[config.postName] = tempArr;

            ZM.ajax( {
                url :config.url,
                success : function(r) {
                    config.grid.getEl().unmask();
                    Ext.Msg.alert(Ext.langs.success, r.detail, success);
                },
                failure : function(r) {
                    config.grid.getEl().unmask();
                },
                params :params
            });
            // ///
        }
    });
}


/**
 * 
 * @param {grid}
 *            需要处理的表格
 * @param {recordXml}
 *            单行record的xml格式 "<record><id>{0}</id><quantity>{1}</quantity></record>"
 * @param {dataIndexArr}
 *            与recordXml对应的数组字段
 */
ZM.gridEditorBatch = function(config) {
    // Ext.Msg.confirm('确定操作?', '你确定要进行此次操作!',
    // function(btn){
    // if(btn == 'yes'){
    // ///
    function q(s) {
        return ("'" + s + "'");
    }
    var recordes = '';
    var wrap = config.wrap || 'records';
    var paramsxml = config.paramsxml || '';
    var docStore = config.grid.getStore();
    docStore.each( function(item) {
        var rs = [];
        Ext.each(config.dataIndexArr, function(dataIndex) {
            rs.push(q(item.get(dataIndex) || ''));
        })

        rs.unshift(q(config.tplxml));
        rs = rs.join(',');
        recordes += eval('String.format(' + rs + ')');
    })

    var success = config.success || function() {
        docStore.reload();
    };

    var requestXml = String.format(
            '<requestXml>{2}<{0}>{1}</{0}></requestXml>', wrap, recordes,
            paramsxml);

    config.grid.getEl().mask(Ext.langs.processing, 'x-mask-loading');

    ZM.ajax( {
        url :config.url,
        success : function(r) {
            config.grid.getEl().unmask();
            Ext.Msg.alert(Ext.langs.success, r.detail, success);
        },
        failure : function(r) {
            config.grid.getEl().unmask();
        },
        params : {
            'requestXml' :requestXml
        }
    });
    // ///
    // }
    // }
    // );
}

ZM.validGrid = function(grid) {
    var columnModel = grid.getColumnModel();
    var colCount = columnModel.getColumnCount();
    var rowCount = grid.getStore().getCount();

    if (rowCount < 1 && !grid.allowBlank) {
        Ext.Msg.alert(Ext.langs.error, Ext.langs.rowIsFilled)
        return false;
        return;
    }

    var SelectionModel = grid.getSelectionModel();
    var selections = SelectionModel.selections;
    // 更新添加行号出现的bug
    var check = false;
    Ext.each(grid.colModel.config, function(item) {
        if (item.id == 'checker')
            check = true;
        ;
    });
    // console.log(selections.items);
    grid.stopEditing();
    if (check) {
        var sel = selections.items;
        for ( var i = 0; i < sel.length; i++) {
            var item = sel[i]
            // Ext.each(selections.items,function(item){
            var r;
            grid.store.each( function(a, b) {
                if (a == item)
                    r = b;
            })

            for ( var c = 0; c < colCount; c++) {

                var cell = columnModel.getCellEditor(c, r);

                if (cell) {
                    if (cell.field.allowBlank == false) {
                        var cn = columnModel.getDataIndex(c);
                        if (grid.store.getAt(r).data[cn] === '') {
                            grid.startEditing(r, c);
                            return false;
                            return;
                        }
                    }
                    //
                    if (cell.field.allowZero == false) {
                        var cn = columnModel.getDataIndex(c);
                        if (grid.store.getAt(r).data[cn] == '0') {
                            grid.startEditing(r, c);
                            cell.field.markInvalid('not 0');
                            return false;
                            return;
                        }
                    }
                    //
                }
            }
        }
    } else {
        for ( var r = 0; r < rowCount; r++) {
            for ( var c = 0; c < colCount; c++) {
                var cell = columnModel.getCellEditor(c, r);
                if (cell) {
                    if (cell.field.allowBlank == false) {
                        var cn = columnModel.getDataIndex(c);
                        if (grid.store.getAt(r).data[cn] === '') {
                            grid.startEditing(r, c);
                            return false;
                            return;
                        }
                    }
                    //
                    if (cell.field.allowZero == false) {
                        var cn = columnModel.getDataIndex(c);
                        if (grid.store.getAt(r).data[cn] == '0') {
                            grid.startEditing(r, c);
                            cell.field.markInvalid('not 0');
                            return false;
                            return;
                        }
                    }
                    //
                }
            }
        }
    }

    return true;
}
/**
 * @grid 提交表格
 */
ZM.submitGrid = function(config) {
    var config = config || {};
    if (!config.grid || !config.options || !config.url || !config.name) {
        Ext.Msg.alert(Ext.langs.error, 'grid,options,url,name needed!');
        return;
    }
    Ext.applyIf(config, {
        success :Ext.emptyFn,
        failure :Ext.emptyFn,
        params : {}
    });

    var grid = config.grid;
    var params = config.params;
    var SelectionModel = grid.getSelectionModel();
    var selections = SelectionModel.selections;

    var check = false;
    Ext.each(grid.colModel.config, function(item) {
        if (item.id == 'checker')
            check = true;
        ;
    });

    if (check && selections.length < 1) {
        Ext.MessageBox.alert(Ext.langs.error, Ext.langs.noItemSeleced);
        return;
    }
    ;

    if (check) {
        Ext.each(selections.items,
                function(item, i) {
                    for (z = 0; z < config.options.length; z++) {
                        params[String.format('{0}[{1}].{2}', config.name, i,
                                config.options[z][0])] = item
                                .get(config.options[z][1]);
                    }
                })
    } else {
        grid.store
                .each( function(item, i) {
                    for (z = 0; z < config.options.length; z++) {
                        params[String.format('{0}[{1}].{2}', config.name, i,
                                config.options[z][0])] = item
                                .get(config.options[z][1]);
                    }
                })
    }

    Ext.getBody().mask(Ext.langs.processing, 'x-mask-loading');

    ZM.ajax( {
        url :config.url,
        success : function(r) {
            Ext.getBody().unmask();
            Ext.Msg.alert(Ext.langs.success, r.detail, function() {
                grid.store.reload();
                config.success();
            });
        },
        failure : function(r) {
            Ext.getBody().unmask();
            config.failure();
        },
        params :params
    });
};

/**
 * @form 提交的表单
 */
ZM.submitForm = function(fs) {
    if (!fs)
        return;
    
    Ext.apply(this,{
        url: fs.url||'',
        success: fs.success || Ext.emptyFn,
        failure: fs.failure || Ext.emptyFn,
        params: fs.params || {},
        crossDomain: fs.crossDomain || false,
        form:fs.form
    });
    
    var _this = this;
    
    fs.items.each( function(f) {
        // 专门处理一个autoComplete
            if (f.xtype === 'autocomplete' && f.allowBlank === false
                    && f.getValue() === '') {
                f.setValue('').focus();
                return false;
            }
            try {
                if (!f.isValid()) {
                    f.focus();
                    return false;
                }
            } catch (e) {
            }
            if(f.getXType() == 'checkbox' && f.disabled == false && f.submitValue == true && f.getValue() === false && Ext.isDefined(f.uncheckedValue)) {
                 _this.params[f.getName()] = f.uncheckedValue;
            }
    });

    this._handler = function(f,action) {
        var responseInfo = this.crossDomain === true ? action : Ext.decode(action.response.responseText) ;
        if( responseInfo.success === true) {
            this.form.items.each(function(item) {
                try{
                    if(Ext.isDefined(item.value)){
                        item.originalValue=item.getValue();
                    }
                }catch(e){}
            });
        
            Ext.getBody().unmask();
            this.success(responseInfo);
        } else {
            Ext.getBody().unmask();
            if(!action.result){
                action.result = {};
                action.result.detail = Ext.langs.loadTimeout;
            }
            Ext.Msg.alert(Ext.langs.error, action.result.detail, function() {
                if (action.result.addon.fatal) {
                    location.reload();
                } else {
                    _this.failure(action.result);
                }
            });
        }
    }
    
    if (fs.getForm().isValid()) {
        fs.items.each( function(f) {
            f.blur();
        });
        Ext.getBody().mask();

        fs.getForm().submit( {
            url:this.url,
            waitTitle :Ext.langs.wait,
            waitMsg :Ext.langs.processing,
            failure : this._handler.createDelegate(this),
            params :this.params,
            success :this._handler.createDelegate(this)
                
        });
    }
};

ZM.validateForm = function(fs) {
    var success = true;
    fs.items.each( function(f) {
        // 专门处理一个autoComplete
            if (f.xtype === 'autocomplete' && f.allowBlank === false
                    && f.getValue() === '') {
                f.setValue('').focus();
                success = false;
                return false;
            }
            try {
                if (!f.isValid()) {
                    f.focus();
                    success = false;
                    return false;
                }
            } catch (e) {
            }
    });
};


ZM.filterXML = function(str) {
    return (str.replace(/<\w+>undefined<\/\w+>/g, ''));
}

ZM.str2Number = function(str) {
    if (Ext.type(str) == 'number')
        return str;
    str = str.replace(/\D+/, "");
    return str
}

// ------------------------renderer--------------------//
ZM.change = function(val) {
    if (val > 0) {
        return '<span style="color:green;">' + val + '</span>';
    } else if (val < 0) {
        return '<span style="color:red;">' + val + '</span>';
    }
    return val;
}
ZM.shortName = function(val) {
    if (val.length > 15) {
        return val.substr(0, 50) + '...';
    }
    return val;
}
// _eof 千分位和小数
ZM.timer = function(v) {
    if (v == null || v == ''|| v == '0000-00-00 00:00:00') {
        return '';
    }
    if (Date.parseDate(v, "Y-m-d h:i:s")) {
        return Date.parseDate(v, "Y-m-d h:i:s").format('Y-m-d');
    }
    return v;
    //return v.substr(2);
}



// renerder 数组对应的id
ZM.id2name = function(v, arr) {
    for (x in arr) {
        if (arr[x][0] == v)
            return arr[x][1]
    }
}

// 状态
ZM.status = function(v) {
    if (v == 1) {
        return '<div class="grid_icon statu_on"></div>';
    } else if (v == 0) {
        return '<div class="grid_icon statu_off"></div>';
    } else if (v == -1) {
        return '<div class="grid_icon statu_pending"></div>';
    } 
    return v;
}

//关联
ZM.linked = function(v) {
    if (v == 1) {
        return '<div class="grid_icon linked"></div>';
    } else if (v == 0) {
        return '<div class="grid_icon unlinked"></div>';
    }
    return v;
}

//锁定
ZM.locked = function(v) {
    if (v == 1) {
        return '<div class="grid_icon locked"></div>';
    } else {
        return '<div class="grid_icon unlocked"></div>';
    }
    return v;
}
//是否可接收短信
ZM.sms = function(v) {
    if (v == 1) {
        return '<div class="grid_icon smsable"></div>';
    } else {
        return '<div class="grid_icon unsmsable"></div>';
    }
    return v;
}

//短信类型
ZM.smsType = function(v) {
    if (v == 1) {
        return '<div class="grid_icon sms_out"></div>';
    } else if(v == 2){
        return '<div class="grid_icon sms_in"></div>';
    }
    return '';
}
//是否可配送
ZM.distributable = function(v) {
    if (v == 1) {
        return '<div class="grid_icon distributable"></div>';
    } else {
        return '<div class="grid_icon undistributable"></div>';
    }
    return v;
}

//正负分数
ZM.score = function(v) {
    if(v<0) return '<span style="color:red;">'+v+'</span>';
    return '<span style="color:green;">'+v+'</span>';
}

//电话接入拨出
ZM.call = function(v) {
    if (v == 2) return '<div class="grid_icon phone_out"></div>';
    else if(v ==1)return '<div class="grid_icon phone_in"></div>';
    return '';
}

//attachment
ZM.attachment = function(v) {
    if (v) {
        return '<div class="grid_icon attachement"></div>';
    }
    return '';
}

//grid filter combo
ZM.filterComboAll = function(arr){
    return [['',Ext.langs.all]].concat(arr);
}

//grid cell renderer
ZM.cellImage = function(src){
    return (src!='') ? ('<a href="'+src.replace('/t/','/o/')+'" target="_blank"><img src="'+src+'" width="100"></a>') : '';
}
ZM.cellUrl = function(url){
    return (url!='') ? ('<a href="'+url+'" target="_blank">'+url+'</a>') : '';
}

Ext.apply(Ext.form.VTypes, {
    daterange : function(val, field) {
        var date = field.parseDate(val);

        if (!date) {
            return;
        }
        if (field.startDateField
                && (!this.dateRangeMax || (date.getTime() != this.dateRangeMax
                        .getTime()))) {
            var start = Ext.getCmp(field.startDateField);
            start.setMaxValue(date);
            start.validate();
            this.dateRangeMax = date;
        } else if (field.endDateField
                && (!this.dateRangeMin || (date.getTime() != this.dateRangeMin
                        .getTime()))) {
            var end = Ext.getCmp(field.endDateField);
            end.setMinValue(date);
            end.validate();
            this.dateRangeMin = date;
        }
        /*
         * Always return true since we're only using this vtype to set the
         * min/max allowed values (these are tested for after the vtype test)
         */
        return true;
    },

    password : function(val, field) {
        if (field.initialPassField) {
            var pwd = Ext.getCmp(field.initialPassField);
            return (val == pwd.getValue());
        }
        return true;
    },
    passwordText :Ext.langs.passwordNotMatch
});


ZM.text2html = function(str) {
    return str.replace(/\\n/gi, '<br />').replace(/\\\\/gi, '\\');
}
ZM.evalText = function(str) {
    if (str)
        return str.replace(/\\n/gi, '\n').replace(/\\\\/gi, '\\');
    return '';
}
/*
 * config.grid为所选grid config.field为对应的列
 */
ZM.sumField = function(config) {
    var n = 0;
    config.grid.getStore().each( function(item) {
        n += Number(item.get(config.field));
    })
    return n;
}
// 多维数组拼音排序
function sortKey(a, b) {
    return (a[0] - b[0]) > 0;
}
function sortValue(a, b) {
    return a[1].localeCompare(b[1]);
}
function date2time(date){
    if(!date)
        return;
    return new Date(date.replace(/-/g,'/')).getTime();
}
function getCookie(c_name)
{
var i,x,y,ARRcookies=document.cookie.split(";");
for (i=0;i<ARRcookies.length;i++)
{
  x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
  y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1);
  x=x.replace(/^\s+|\s+$/g,"");
  if (x==c_name)
    {
    return unescape(y);
    }
  }
}
ZM.moveSelectedRow = function (grid, direction,record) {
    var record = record || grid.getSelectionModel().getSelections()[0];
    if (!record) {
        return;
    }
    var index = grid.getStore().indexOf(record);
    if(direction == 1) {
        index++;
        if (index >= grid.getStore().getCount()) {
            return;
        }
    } else if(direction == 2) {
        index = grid.getStore().getCount()-1;
    } else if(direction == -1) {
        index--;
        if (index < 0) {
            return;
        }
    } else if(direction == -2) {
        index = 0 ;
    } else {
        return ;
    }
    grid.getStore().remove(record);
    grid.getStore().insert(index, record);
    grid.getSelectionModel().selectRow(index, true);
}
ZM.treeRefresh = function(tree) {
        var root = tree.getRootNode();
        var arrayNode = getExpandedTreeNode(root);
        tree.getLoader().load(root,function(){
                Ext.each(arrayNode,function(path) {
                    tree.expandPath(path);
                });
            });
        function getExpandedTreeNode (node) {
            if(node.isExpanded()) {
                var arr = [node.getPath()]
                Ext.each(node.childNodes,function(n) {
                    arr = arr.concat(getExpandedTreeNode(n));
                });
                return arr;
            } 
            return [];
        }
    } 
    
Date.prototype.format = function(fmt)   
{ //author: meizz   
  var o = {   
    "M+" : this.getMonth()+1,                 //月份   
    "d+" : this.getDate(),                    //日   
    "h+" : this.getHours(),                   //小时   
    "m+" : this.getMinutes(),                 //分   
    "s+" : this.getSeconds(),                 //秒   
    "q+" : Math.floor((this.getMonth()+3)/3), //季度   
    "S"  : this.getMilliseconds()             //毫秒   
  };   
  if(/(y+)/.test(fmt))   
    fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));   
  for(var k in o)   
    if(new RegExp("("+ k +")").test(fmt))   
  fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));   
  return fmt;   
}

ZM.loadFormData = function(form,record) {
    function setVal(fieldId, val) {
        var field = form.findField(fieldId);
        if (field) {
            field.setValue(val);
            if (form.trackResetOnLoad) {
                field.resetOriginalValue();
            }
        }
    }

    if (Ext.isArray(record)) {
        // array of objects
        Ext.each(record, function(val) {
            setVal(val.id, val.value);
        });
    } else if(Ext.isObject(record)){
        // object hash
        // Ext.iterate(record, setVal);
        for(var obj in record) {
            setVal(obj,record[obj]);
        }
    }
}
ZM.showTime = function(time) {
    return time=='0000-00-00 00:00:00'?'':time;
}

ZM.showImage = function(val) {
    return '<img src='+val+' height="48" ' +
        'onerror="javascript:this.src=\'/ys-pub/resources/images/ZM/img_not_found.gif\';" />';
}
ZM.floatFix = function(val,len) {
    return Math.round(val*Math.pow(10,len))/Math.pow(10,len);
}

ZM.loadJsCssFile = function(name,type,code) {
    if (type=="js"){
        var fileref=document.createElement('script');
        fileref.setAttribute("type","text/javascript");
        fileref.setAttribute("src", name);
        code && fileref.setAttribute("charset", code);
    } else if (type=="css"){
        var fileref=document.createElement("link");
        fileref.setAttribute("rel", "stylesheet");
        fileref.setAttribute("type", "text/css");
        fileref.setAttribute("href", name);
    }
    if (typeof fileref!="undefined") {
        document.getElementsByTagName("head")[0].appendChild(fileref);
        fileref.onload = function() {
            Ext.getBody().unmask();
        }
    }
}

 /**Parses string formatted as YYYY-MM-DD to a Date object.
 * If the supplied string does not match the format, an
 * invalid Date (value NaN) is returned.
 * @param {string} dateStringInRange format YYYY-MM-DD, with year in
 * range of 0000-9999, inclusive.
 * @return {Date} Date object representing the string.
 */

 ZM.parseDate = function (dateStringInRange) {
    var isoExp = /^\s*(\d{4})-(\d\d)-(\d\d)\s*$/,
        date = new Date(NaN), month,
        parts = isoExp.exec(dateStringInRange);
    if(parts) {
        month = +parts[2];
        date.setFullYear(parts[1], month - 1, parts[3]);
        if(month != date.getMonth() + 1) {
            date.setTime(NaN);
        }
    }
    return date;
}

ZM.resetForm =function(frm,fucosName){
    var firstFocus = false;
    frm.items.each(function(f){
        if(!f.notReset && f.xtype != 'button') {
            f.setValue(f.initialConfig.value);
        }
        if(!firstFocus&& f.xtype != 'displayfield'&& f.xtype!='radiogroup'&&f.xtype!='checkboxgroup'&&(!fucosName || fucosName== f.name)) {
            setTimeout(function(){f.focus(true);},300);
            firstFocus = true;
        }
    });
}

ZM.clearArrayParam = function(params,name) {
    for(var i = 0; ;i++) {
        var key = name+'['+i+']';
        if(!Ext.isDefined(params[key])) break;
        delete params[key];
    }
}

ZM.wrapTag = function(el, tag) {
    switch(tag)
    {
    case 100:
      tag = 'div'
      break;
    case 112:
      tag = 'p'
      break;
    case 104:
      tag = 'h2'
      break;
    case 119:
      tag = 'widget'
      break;
    default:
      tag = 'p'
    }
    var textarea = el,sel = {},val = el.value;;
    if (textarea.setSelectionRange) { // W3C
        sel.start= textarea.selectionStart;
        sel.end = textarea.selectionEnd;

        var text = '<'+tag+'>'+val.slice(sel.start,sel.end)+'</'+tag+'>';
        el.value = val.slice(0, sel.start) + text + val.slice(sel.end);
    }
}
ZM.insertAtCursor = function(myField, myValue) {
    var rangData = ZM.getCursorPosition(myField);
    var restoreTop = myField.scrollTop;
    if(myValue == '\t') {
        var textarea = myField;
        var s = textarea.value.substring(0,rangData.start).lastIndexOf('\n')
            ,s = s > -1 ? s + 1: 0,
            n = 0;
        while(true) {
            textarea.value = textarea.value.substring(0,s) + '\t' + textarea.value.substring(s);
            n++;
            rangData.end += 1;
            var pos = textarea.value.substring(s,rangData.end).indexOf('\n');
            if(pos == -1) break;
            s = s+pos+1;
        }
        rangData.start += 1;
    } else {
        myField.value = myField.value.substring(0,rangData.start) + myValue + myField.value.substring(rangData.start);
        rangData.start = (rangData.end += myValue.length);
    }
    ZM.setCursorPosition(myField,rangData);
    if (restoreTop>0){
        myField.scrollTop = restoreTop;
    }
}

ZM.getCursorPosition = function(textarea) {
    var rangeData = {text: "", start: 0, end: 0 };
    textarea.focus();
    if (textarea.setSelectionRange) { // W3C
        rangeData.start= textarea.selectionStart;
        rangeData.end = textarea.selectionEnd;
        rangeData.text = (rangeData.start != rangeData.end) ? textarea.value.substring(rangeData.start, rangeData.end): "";
    } else if (document.selection) { // IE
        var i,
            oS = document.selection.createRange(),
            // Don't: oR = textarea.createTextRange()
            oR = document.body.createTextRange();
        oR.moveToElementText(textarea);

        rangeData.text = oS.text;
        rangeData.bookmark = oS.getBookmark();

        // object.moveStart(sUnit [, iCount])
        // Return Value: Integer that returns the number of units moved.
        for (i = 0; oR.compareEndPoints('StartToStart', oS) < 0 && oS.moveStart("character", -1) !== 0; i ++) {
            // Why? You can alert(textarea.value.length)
            if (textarea.value.charAt(i) == '\n') {
                i ++;
            }
        }
        rangeData.start = i;
        rangeData.end = rangeData.text.length + rangeData.start;
    }

    return rangeData;
}

ZM.setCursorPosition = function(textarea, rangeData) {
    if(!rangeData) {
        alert("You must get cursor position first.")
    }
    //scroll pre pos
        // if (textarea.scrollTop>0){
//          textarea.scrollTop = restoreTop;
//      }
    if (textarea.setSelectionRange) { // W3C
        textarea.focus();
        textarea.setSelectionRange(rangeData.start, rangeData.end);
        
    } else if (textarea.createTextRange) { // IE
        var oR = textarea.createTextRange();
        // Fixbug :
        // In IE, if cursor position at the end of textarea, the setCursorPosition function don't work
        if(textarea.value.length === rangeData.start) {
            oR.collapse(false)
            oR.select();
        } else {
            oR.moveToBookmark(rangeData.bookmark);
            oR.select();
        }
    }
}

ZM.replaceText = (function(r){
 return function(text,find, replace, replaceOnce) {
     if(typeof find == 'string' && !replaceOnce) {
       find = r.apply(find, [/[\[\]^$*+.?(){}\\\-]/g,function(c) { return '\\'+c; }]);
       find = new RegExp(find, 'g');
     } else if(typeof find == 'object' && !replaceOnce && !find.global) {
       find = new RegExp(find.source, 'g');
     }
     return r.apply(text, [find,replace]);
 }
})(String.prototype.replace);

ZM.hideColumn = function(grid,dataIndex,status) {
    var cm = grid.getColumnModel();
    var col = cm.findColumnIndex(dataIndex);
    cm.setHidden(col,status);
}

ZM.addEditorRow = function (grid,col) {
    if(!Ext.isDefined(col)) {
        col = 0;
    }
    var store = grid.store;
    var recode = store.recordType; 
    var p = new recode({});
    grid.stopEditing();  
    store.add(p);
    grid.getView().refresh();
    var row = store.getCount()-1;
    grid.getSelectionModel().selectRow(row);
    grid.startEditing(row, col);
    grid.getView().getRow(row).scrollIntoView();
}

ZM.removeEditorRow = function (grid,r) {
    var store = grid.store;
    grid.stopEditing();  
    var row = store.indexOf(r);
    if(row == -1) return;
    store.removeAt(row);
    grid.getView().refresh();
    row = Math.min(row,store.getCount() -1);
    grid.getSelectionModel().selectRow(row);
    grid.getView().getRow(row).scrollIntoView();
}

ZM.initSourceCombo = function(data,preData) {
    var arr = preData||[];
    Ext.each(data,function(d) {
        arr.push([d.id,d.name]);
    });
    return arr;
};

ZM.initLinkedCombo = function(data,sourceValue,preData) {
    var arr = preData||[];
    Ext.each(data,function(item) {
        if(item.id == sourceValue) {
            Ext.each(item.children,function(d) {
                arr.push([d.id,d.name]);
            });
            return true;
        }
    });
    return arr;
};

ZM.updateLinkedCombo = function(sourceCombo,targetCombo,data,preData) {
    var val = sourceCombo.getValue();
    Ext.each(data,function(item) {
        if(item.id == val) {
            var arr = preData||[];
            Ext.each(item.children,function(d) {
                arr.push([d.id,d.name]);
            });
            if(item.id != targetCombo.getValue()) {
                targetCombo.setValue('');
            }
            targetCombo.updateOptions(arr);
            return true;
        }
    });
};

ZM.defaultLeftNav = {xtype:'container',width:5,region:'west',style:'background-color: #AAAAAA;'};

ZM.NavBar = function(config) {
    var config = config || {};
    Ext.applyIf(config,{
        region:'north',
        height:35,
        border:false,
        logocls:(config.logo)?' style="padding-left:175px;"':'',
        logoel:(config.logo)?'<img src="'+config.logo+'" style="position:absolute;top:0;left:10px" />':'',
        listeners: {
            'render': function(){
                var tpl = new Ext.XTemplate(
                    '<div id="header" class="{cls}"><div class="head_ml"><div class="head_mr"><div class="head_mc"{logocls}>',
                    '<table><tr>',
                    '<tpl for="childs">',
                    '<td class="{[values.id == ((typeof navActive !== "undefined")?navActive:Ext.navActive) ? "active" : "odd"]}"><a href="{url}" target="{[values.target||\"_top\"]}"><span>{text}</span></a></td>',
                    '</tpl>',
                    '</tr></table>',
                    '{logoel}<div class="info">{info}</div>',
                    '</div></div></div></div>'
                );
                tpl.overwrite(this.body, config);
            }
        }
    });
    // call the superclass's constructor 
    ZM.NavBar.superclass.constructor.call(this, config);
};
Ext.extend(ZM.NavBar, Ext.Panel);

ZM.menuAction = function(config){
    Ext.apply(this, config);
    ZM.menuAction.superclass.constructor.call(this);
};

Ext.extend(ZM.menuAction, Ext.util.Observable, {
    init : function(p){
        p.on('afterrender', function(){
            var actionBody = p.body;
            if(Ext.actions&&!Ext.isEmpty(Ext.actions)){
                actionBody.on('mouseup', function(e, t) {
                    try {
                        e.stopEvent();
                    } catch (e) {
                    }
                    ;
                    if (e.button > 0)
                        return;
                    if (!(t.id))
                        return;
                    var bd = Ext.getCmp('action-panel').body;
                    bd.select('li').removeClass('selected');
                    Ext.fly(t.parentNode).addClass('selected');
                    // 进行action处理
                    try {
                        Ext.actions[t.id]();
                        //Ext.getCmp('main-panel').setTitle(t.title);
                    } catch (err) {
                        if(e.getTarget().target!='_blank'){
                            location.href = t.id;
                        }else{
                            window.open(t.id);
                        };
                        //
                    }

                }, null, {delegate:'a'/*,buffer:250*/});
                actionBody.on('click', Ext.emptyFn, null, {delegate:'a', preventDefault:true});
            }
        }, this);
    }
});

ZM.ActionPanel = function(config) {
    var config = config || {};
    Ext.applyIf(config,{
        id:'action-panel',
        region:'west',
        split:true,
        collapsible: true,
        collapseMode: 'mini',
        header: false,
        width:240,
        autoScroll:true,
        plugins:[new ZM.menuAction()],
        defaults:{xtype:'menupanel'},
        minWidth: 150,
        border: false,
        baseCls:'x-plain',
        maxWidth:350
    });
    // call the superclass's constructor 
    ZM.ActionPanel.superclass.constructor.call(this, config);
};
Ext.extend(ZM.ActionPanel, Ext.Panel);
Ext.reg('actionpanel', ZM.ActionPanel);

ZM.detailPanel = function(config) {
    var config = config || {};
    //重构tbar
    config.listeners = config.listeners || {};
    var tbar = config.tbar||[];
    var closeTbar = ['->',{
                icon: Ext.imagePath +'icon-close.gif',
                cls: 'x-btn-icon',
                handler : function(){
                    Ext.getCmp('bottom-preview').hide().ownerCt.doLayout();
                }
            }];
    config.tbar = [];
    config.listeners['afterrender'] = function(p) {
        var grid = p.get(0);
        if(grid.getXType() == 'gridpanel' && grid.saveSortCfg) {
            tbar = tbar.concat(grid.initialConfig.tbar);
            tbar = tbar.concat(closeTbar);
            grid.getTopToolbar().removeAll();
            p.getTopToolbar().add(tbar);
        } else {
            tbar = tbar.concat(closeTbar);
            p.getTopToolbar().add(tbar);
        }
//         p.getTopToolbar().doLayout();
    };
    Ext.applyIf(config,{
        id:'bottom-preview',
        layout:'fit',
        hidden:true,
        height: 250,
        split: true,
        border:false,
        region:'south'
    });
    ZM.detailPanel.superclass.constructor.call(this, config);
};

Ext.extend(ZM.detailPanel, Ext.Panel);
Ext.reg('detailpanel', ZM.detailPanel);

ZM.MenuPanel = function(config) {
    var config = config || {};
    Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
    Ext.applyIf(config,{
        frame:true,
        title: 'menu panel',
        collapsible:true,
        titleCollapse: true,
        listeners: {
            'render': function(){
                var tpl = new Ext.XTemplate(
                    '<ul><tpl for=".">',
                    '<li{[values.url == ((typeof menuUrl !== "undefined")?menuUrl:Ext.menuUrl) ? " class=selected" : ""]}><img src="', Ext.BLANK_IMAGE_URL, '" class="{[values.iconCls ? values.iconCls : "icon-page"]}"/>',
                    '{[(values.disabled == true)? "<span class=\'gray\'>"+values.text+"</span>" : (values.target)?"<a href=\'"+values.url+"\' target=\'"+values.target+"\' id=\'"+values.url+"\' title=\'"+values.text+"\'>"+values.text+"</a>":"<a href=\'"+values.url+"\' target=\'_top\' id=\'"+values.url+"\' title=\'"+values.text+"\'>"+values.text+"</a>"]}',
                    '</li>',
                    '</tpl></ul>'
                );

                this.collapsed = Ext.state.Manager.get(this.id);
                tpl.overwrite(this.body, this.childs);
            },
            'beforecollapse': function() {
                Ext.state.Manager.set(this.id, true);
                //console.log(Ext.state.Manager.get(this.id));
            },
            'beforeexpand': function() {
                Ext.state.Manager.set(this.id, false);
            }
        }
    });
    // call the superclass's constructor 
    ZM.MenuPanel.superclass.constructor.call(this, config);
};
Ext.extend(ZM.MenuPanel, Ext.Panel);
Ext.reg('menupanel', ZM.MenuPanel);

ZM.MainPanel = function(config) {
    var config = config || {};
    Ext.applyIf(config,{
        id:'main-panel',
        title:'mainpanel',
        frame:true,
        border:true,
        bodyStyle:'background:#fff;',
        region:'center'
    });
    // call the superclass's constructor 
    ZM.MainPanel.superclass.constructor.call(this, config);
};
Ext.extend(ZM.MainPanel, Ext.Panel);
Ext.reg('mainpanel', ZM.MainPanel);

//plugin for HeaderForm
ZM.HeaderForm = function (config) {
    Ext.apply(this, config);
    ZM.HeaderForm.superclass.constructor.call(this);
};

Ext.extend(ZM.HeaderForm, Ext.util.Observable, {
    obj:{},
    $this:{},

    init : function (grid)
    {
        if(!grid.id)
            grid.id = Ext.id();

        this.obj[grid.id] = {};
        this.$this = this.obj[grid.id];
        var $this = this.$this;

        $this.filterPanels = [];
        $this.filterFields = {};
        $this.firstActive = true;
        $this.applyFilter = this.applyFilter;
        //$this = this.obj[grid.id];

        $this.grid = grid;
        $this.cm = $this.grid.getColumnModel();
        $this.cols = $this.cm.getColumnsBy(function(){return true});

        $this.listener = {
            "keypress": function(el,ev){
                ev.stopPropagation();

                if(ev.getKey() == Ext.EventObject.ENTER)
                {
                    $this.applyFilter();
                    el.el.dom.blur();
                }
            },
            "keyup": function(el,ev){
                ev.stopPropagation();
                if(ev.getKey() == Ext.EventObject.ESC)
                {
                    for (v in $this.filterFields){
                        el = $this.filterFields[v];
                        //el.setValue('')
                        el.reset();
                    }
                    $this.applyFilter();
                    el.el.dom.blur();
                }
            }
        },

            //判断是否有filter这个属性，如果有，则表头加载过滤条
            Ext.each($this.cols,function(item){
                if(item.filter)
                    $this.useFilter = true;
            })

        //filter is start 
        $this.grid.reconfigure = $this.grid.reconfigure.createSequence(this.reconfigure, this);
        $this.grid.afterRender = $this.grid.afterRender.createSequence(this.afterRender, this);
        if($this.useFilter){
            $this.grid.on("resize", this.syncFields, this);
            $this.grid.on("columnresize", this.syncFields, this);
            //$this.grid.getColumnModel().on('hiddenchange',this.syncFields,this);//显示与隐藏列不调整filter的宽度
        }
       
        this.reconfigure();
    },


    //创建表头基本元素
    createHeader : function ()
    {
        var $this = this.$this;
        $this.bodyTpl = new Ext.Template(
            '<tbody><tr class="head-filter">{rows}</tr></tbody>'
        );

        var rows = [];
        var rowShow = new Ext.Template(
            '<td><div class="x-small-editor" id="filter_{id}"></div></td>'
        );

        var rowHide = new Ext.Template(
            '<td style="display:none"><div class="x-small-editor" id="filter_{id}"></div></td>'
        );

        Ext.each($this.cols,function(item){
            if(item.hidden){
                rows.push(rowHide.apply({id: $this.grid.id+item.dataIndex}));
            }else{
                rows.push(rowShow.apply({id: $this.grid.id+item.dataIndex}));
            }
        })

        //第一次则创建对像
        if(!$this.grid.getView().templates)
            $this.grid.getView().templates = {};

        var strSearchEl = '';
        if($this.grid.search) {
            strSearchEl = '<div class="ZM-search" id="search-'+$this.grid.id+'"></div>';
        }
        if($this.useFilter){
            $this.grid.getView().templates.header = new Ext.Template(
                strSearchEl+'<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
                '<thead><tr class="x-grid3-hd-row">{cells}</tr></thead>',
                $this.bodyTpl.apply({rows: rows.join("")}),
                '</table>'
            );
        }else{
            $this.grid.getView().templates.header = new Ext.Template(
                strSearchEl+'<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
                '<thead><tr class="x-grid3-hd-row">{cells}</tr></thead>',
                '</table>'
            );
        }
    },

    //创建额外表头表单元素
    createSearchPanel: function (){
        $this = this.$this;
        var tempArr = [];
        Ext.each($this.grid.search,function(item){
            item.filterName = item.name;
            item.enableKeyEvents = true;
            if(!item.listeners)
                item.listeners = $this.listener;
            //if(item.submitValue!==false)
            if(item.xtype == 'textfield') {
                item.xtype = 'trigger';
                item.listeners = item.listeners || {};
                item.onTriggerClick = function(){
                    $this.applyFilter();
                };
                item.triggerClass = 'x-form-search-trigger';
                item.hideTrigger = true;
            }
            tempArr.push(item);
        });

        var searchPanel = new Ext.Panel({
            renderTo: 'search-' + $this.grid.id,
            layout: "form",
            labelWidth:75,
            labelAlign:'right',
            defaultType: 'textfield',
            //defaults:{selectOnFocus:true},
            items: tempArr,
            bodyStyle: 'padding:5px 1px;background:#DDD', /* CAD9EC */
            stateful: false
        });

        if($this.grid.autoSearch) {
            searchPanel.items.each(function(item) {
                if(item.xtype == 'trigger') {
                    item.el.on({
                        mouseenter:function(e,t)  {
                            this.setHideTrigger(false);
                        },
                        mouseleave:function(e,t) {
                            this.setHideTrigger(true);
                        },
                        scope:filterPanel.get(0)
                    });
                } else if(item.xtype == 'combo' || item.xtype == 'combofield' || item.xtype == 'datefield' || item.xtype == 'timefield'){
                    item.on('select',function() {
                        $this.applyFilter();
                    });
                } else {
                    fitem.on('confirm',function() {
                        $this.applyFilter();
                    });
                    item.on('cancel',function() {
                        $this.applyFilter();
                    });
                }
            });
        }

        Ext.each(searchPanel.items.items,function(item,i){
            $this.filterFields[item.filterName]=item;
        });
    },

    createFormFields : function (){
        var $this = this.$this;
        //破坏掉原来的所有面板
        Ext.each($this.filterPanels,function(item){
                item.destroy();
            }
        )
        //json concat
        function jsonConcat(o1, o2) {
            for (var key in o2) {
                o1[key] = o2[key];
            }
            return o1;
        }
        Ext.each($this.cols,function(item){
            if(item.filter){
                var filterConfig = {};

                var tempId = $this.grid.id+ item.dataIndex;
                Ext.apply(filterConfig, item.filter);
                filterConfig.dataIndex = item.dataIndex;
                if(!filterConfig.id)
                    filterConfig.id = 'f_'+ tempId;
                //filterConfig.selectOnFocus= true;
                filterConfig.enableKeyEvents = true;
                if(filterConfig.listeners){
                    filterConfig.listeners =jsonConcat(filterConfig.listeners,$this.listener);
                }else{
                    filterConfig.listeners = $this.listener;
                }
                filterConfig.stateful = false;

                if(!filterConfig.filterName)
                    filterConfig.filterName = filterConfig.name||item.dataIndex;

                filterConfig.xtype = (filterConfig.xtype)?filterConfig.xtype:'textfield';
                if($this.grid.autoSearch) {
                    if(filterConfig.xtype == 'textfield') {
                        filterConfig.xtype = 'trigger';
                        filterConfig.listeners = filterConfig.listeners || {};
                        filterConfig.onTriggerClick = function(){
                            $this.applyFilter();
                        };
                        filterConfig.triggerClass = 'x-form-search-trigger';
                        filterConfig.hideTrigger = true;
                    }
                }
                if(!$this.grid.remoteFilter && (filterConfig.xtype=='trigger'||filterConfig.xtype=='textfield')) {
                    filterConfig.enableKeyEvents = true;
                }

                filterPanel = new Ext.Panel({
                    renderTo: 'filter_' + tempId,
                    id : 'p_' + tempId,
                    layout: "fit",
                    autoWidth:true,
                    defaults:{style:'text-align:left'},
                    items: filterConfig,
                    bodyStyle: 'padding:1px;',
                    stateful: false
                });
                
                if($this.grid.autoSearch) {
                    if(filterConfig.xtype == 'trigger') {
                        filterPanel.el.on({
                            mouseenter:function(e,t)  {
                                this.setHideTrigger(false);
                            },
                            mouseleave:function(e,t) {
                                this.setHideTrigger(true);
                            },
                            scope:filterPanel.get(0)
                        });
                    } else if(filterConfig.xtype == 'combo' || filterConfig.xtype == 'combofield' || filterConfig.xtype == 'datefield' || filterConfig.xtype == 'timefield'){
                        filterPanel.get(0).on('select',function() {
                            $this.applyFilter();
                        });
                    } else {
                        filterPanel.get(0).on('confirm',function() {
                            $this.applyFilter();
                        });
                        filterPanel.get(0).on('cancel',function() {
                            $this.applyFilter();
                        });
                    }
                }

                if(!$this.grid.remoteFilter && (filterConfig.xtype=='trigger'||filterConfig.xtype=='textfield')) {
                    filterPanel.get(0).on('keyup',function(field,e) {$this.applyFilter();});
                }

                //封装原来的对像，等着destroy
                $this.filterPanels.push(filterPanel);

                $this.filterFields[filterConfig.filterName] = filterPanel.items.first();
            }
        })

        this.syncFields();
    },

    //这里处理得有点怪，主要是为了listeners共用
    applyFilter: function()
    {
        var $this = this,
            filterArr = [];
        for (v in $this.filterFields){
            el = $this.filterFields[v];
            //用于验证，只要表单里有不合格的，则所有的查询都不可用
            //希望这里只有一项搜索
            if(el.xtype!='daterangefield'&&!el.isValid())
                return;
            if(el.xtype == 'daterangefield'||el.xtype == 'datetimerangefield'||el.xtype == 'floatrangefield'||el.xtype == 'textrangefield') {
                var sValue = el.getValue().split(el.delimiter);
                if(sValue.length < 2) {
                    delete $this.grid.store.baseParams[el.filterName+'_start'];
                    delete $this.grid.store.baseParams[el.filterName+'_end'];
                } else {
                    $this.grid.store.baseParams[el.filterName+'_start'] = sValue[0]+(el.xtype == 'daterangefield'?' 00:00:00':'');
                    $this.grid.store.baseParams[el.filterName+'_end'] = sValue[1]+(el.xtype == 'daterangefield'?' 23:59:59':'');
                    if(sValue[0]=='') {
                        delete $this.grid.store.baseParams[el.filterName+'_start'];
                    }
                    if(sValue[1]=='') {
                        delete $this.grid.store.baseParams[el.filterName+'_end'];
                    }
                    filterArr.push({xtype:el.xtype,value:el.getValue(),dataIndex:v});
                }
            } else {
                var sValue = el.getValue();
                if(el.xtype == 'datefield') {
                    var sValue =  el.getRawValue();
                }
                if(Ext.isString(sValue) && sValue.trim) {
                    sValue = sValue.trim();
                }
                if(Ext.isArray(sValue)) {
                    sValue = sValue.join(',');
                }
                if(Ext.isEmpty(sValue))
                {
                    delete $this.grid.store.baseParams[el.filterName];
                }
                else
                {
                    $this.grid.store.baseParams[el.filterName] = sValue;
                    filterArr.push({xtype:el.xtype,value:sValue,dataIndex:v});
                }
            }
        };

        if(!$this.grid.remoteFilter) { //是否使用后台搜索
            $this.grid.store.filterBy(function(record) {
                for(var i=0; i<filterArr.length; i++) {
                    var dataIndexValue = eval("record.data."+filterArr[i]['dataIndex']);
                    if(filterArr[i]['xtype'] == 'textfield'||filterArr[i]['xtype'] == 'trigger') {
                        if(dataIndexValue.toLowerCase().indexOf(filterArr[i]['value'].toLowerCase()) == -1) {
                            return false;
                        }
                    } else {
                        if(dataIndexValue != filterArr[i]['value']) {
                            return false;
                        }
                    }
                }
                return true;
            });
        } else {
            $this.grid.store.load();
        }
    },

    syncFields : function ()
    {
        $this = this.$this;
        /*fix header table width*/
        $this.grid.view.mainHd.dom.getElementsByTagName('table')[0].style.width = $this.grid.view.getTotalWidth();

        if($this.filterPanels){
            Ext.each($this.filterPanels,function(item,i){
                //console.log(item.id);
                //item.syncSize();
                item.doLayout();

                //fixed ie bug
                if(Ext.isIE){
                    Ext.each($this.cols,function(im,i){
                        if(item.id.substr(2)==im.dataIndex)
                            item.setWidth($this.cm.getColumnWidth(i));
                    })
                }
            })

        }
    },

    reconfigure : function ()
    {
        var $this = this.$this;
        this.createHeader();
        if(!$this.firstActive)
            this.createFormFields();

    },

    afterRender : function ()
    {
        var $this = this.$this;
        this.createFormFields();
        $this.firstActive = false;
        if($this.grid.search)
            this.createSearchPanel();
    }
});

ZM.JsonStore = function(config) {
    var config = config || {};
    config.url = config.url;
    //把超时设置为一分半钟
    //添加跨域处理，如跨域则使用ScriptTagProxy,否则使用HttpProxy
    config.proxy = (config.crossDomain === true ? new Ext.data.ScriptTagProxy({ url: config.url, timeout:config.timeout||90000 }) : new Ext.data.HttpProxy({ url: config.url, timeout:config.timeout||90000 }));

    Ext.applyIf(config,{
        root:"items",
        totalProperty:"totalCount",
        remoteSort:true,
        listeners:{
            'loadexception' : function(v,o){
                try {
                    //console.log(o.reader.jsonData.detail);
                    Ext.Msg.alert(Ext.langs.error, o.reader.jsonData.detail||Ext.langs.loadTimeout);
                }catch (e){
                    //Ext.Msg.alert('加载失败',e);
                }

            }
        }
    })

    ZM.JsonStore.superclass.constructor.call(this, config);
};
Ext.extend(ZM.JsonStore, Ext.data.JsonStore);


/*^^^^^^^^^^^^^^^^Plugins^^^^^^^^^^^^^^^^*/
ZM.IFRAME = Ext.extend(Ext.BoxComponent, {
    onRender : function(ct, position){
        this.el = ct.createChild({tag: 'iframe', id: 'iframe-'+ this.id, name:'iframe-'+this.name, frameBorder: 0, src: this.url});
    }
});


//添加record的操作选项
ZM.RowAction = function(config){
    Ext.apply(this, config);
    ZM.RowAction.superclass.constructor.call(this);
    this.oldRow = {};
};

Ext.extend(ZM.RowAction, Ext.util.Observable, {
    init : function(grid){
        this.grid = grid;
        var view = grid.getView();
        grid.on('render', function(){
            view.mainBody.on('mousedown', this.onMouseDown, this);
        }, this);
        //双击fireDetail
        grid.on('rowdblclick',function(g,r,e){
            var item = g.store.getAt(r);
            try{
                var str = (eval('this.grid.fireDetail(item)'));
                Ext.historyRecord = item;
                if(str===false){
                    return;
                }

                var row = e.getTarget('.x-grid3-row');

                //删除load之前的历史项
                /*
                 为了两个表不冲突,暂时注掉
                 Ext.each(Ext.select('.grid-now').elements,function(item){
                 if(item!=this.rowOld)
                 Ext.fly(item).removeClass('grid-now');
                 })
                 */

                if(g.rowOld){
                    Ext.fly(g.rowOld).removeClass('grid-now');
                    Ext.fly(g.rowOld).addClass('grid-history');
                }
                Ext.fly(row).removeClass('grid-history');
                Ext.fly(row).addClass('grid-now');

                g.rowOld = row;
            }catch(e){
            }

        },this)
    },


    onMouseDown : function(e, t){
        if(t.tagName == 'A' && t.title){

            var fn = eval('this.grid.'+t.title);
            if(!Ext.isFunction(fn))
                return;

            //klj not delete,stop event is must; 
            e.stopEvent();
            var row = e.getTarget('.x-grid3-row');

            //删除load之前的历史项
            /*
             为了两个表不冲突,暂时注掉
             try{
             Ext.each(Ext.select('.grid-now').elements,function(item){
             if(item!=this.rowOld)
             Ext.fly(item).removeClass('grid-now');
             })
             }catch(e){}
             */

            this.toggleRow(row);
            var grid = this.grid;
            this.grid.store.each(function(item){
                if(item.id==t.id.substr(1)){
                    //回调函数
                    var result = '';
                    if(t.href){
                        var regex=/(.*?)#([^\_]+)/;
                        var s = t.href.match(regex);
                        if(s)
                            result=s[2];
                    }
                    var p = grid.findParentByType('mainpanel');
                    if(p && p.findByType('detailpanel').length > 0 && !Ext.get(t).up('#bottom-preview')) {
                        if(Ext.historyRecord && Ext.historyRecord.id != item.id && Ext.getCmp('bottom-preview')) {
                            Ext.getCmp('bottom-preview').hide().ownerCt.doLayout();
                        }
                    }
                    Ext.historyRecord = item;
                    eval('this.grid.'+t.title+'(item,"'+result+'")');
                }
            },this);
            // e.preventDefault();
            // e.stopPropagation();
        }

    },

    toggleRow : function(row){
        if(this.grid.rowOld){
            Ext.fly(this.grid.rowOld).removeClass('grid-now');
            Ext.fly(this.grid.rowOld).addClass('grid-history');
        }
        Ext.fly(row).removeClass('grid-history');
        Ext.fly(row).addClass('grid-now');
        this.grid.rowOld = row;
    }
});

/*显示分页插件 */
Ext.ux.PageSizePlugin = function(config) {
    Ext.apply(this, config);
    Ext.ux.PageSizePlugin.superclass.constructor.call(this, {
        store: new Ext.data.SimpleStore({
            fields: ['text', 'value'],
            data: config.pageOptions||[['10', 10], ['20', 20],['30',30], ['50', 50],['100',100]]
        }),
        mode: 'local',
        forceSelection: true,
        triggerAction: 'all',
        editable:false,
        displayField: 'text',
        valueField: 'value',
        allowBlank: false,
        width: 50,
        maskRe: /[0-9]/
    });
};
Ext.extend(Ext.ux.PageSizePlugin, Ext.form.ComboBox, {
    beforeText:Ext.langs.show,
    afterText:Ext.langs.pageSize,

    init: function(paging) {
        paging.on('render', this.onInitView, this);
    },

    onInitView: function(paging) {
        //paging.add('-', this.beforeText, this, this.afterText);
        paging.insert(11,'-');
        paging.insert(12,this.beforeText);
        paging.insert(13,this);
        paging.insert(14,this.afterText);

        this.setValue(paging.pageSize);
        this.on('select', this.onPageSizeChanged, paging);
        this.on('specialkey', function(combo, e) {
            if(13 === e.getKey()) {
                this.onPageSizeChanged.call(paging, this);
            }
        });

    },

    onPageSizeChanged: function(combo) {
        this.pageSize = parseInt(combo.getRawValue(), 10);
        this.store.baseParams.limit = parseInt(combo.getRawValue(), 10);
        this.doLoad();

        //this.store.load();
    }
});


/*
 *grid处理
 */
var sm = 'sm';

function fixconfig(config,grid){
    var config = config||{};
    if(!Ext.isDefined(config.noRowNumber)) {
        config.noRowNumber = true;
    }
    if(!Ext.isDefined(config.autoSearch)) {
        config.autoSearch = true;
    }
    if(!config.onlyShow){
        config.sm = new Ext.grid.CheckboxSelectionModel({handleMouseDown:Ext.emptyFn,singleSelect:config.singleSelect
                    ,header:config.singleSelect?'<div></div>':'<div class="x-grid3-hd-checker">&#160;</div>'});
    }else{
        config.sm = new Ext.grid.CheckboxSelectionModel({singleSelect:config.singleSelect
                    ,header:config.singleSelect?'<div></div>':'<div class="x-grid3-hd-checker">&#160;</div>'});
    }
    config.region = config.region || 'center';
    //添加history
    config.history = config.history || (config.columns[0] == sm ? config.columns[1].dataIndex : config.columns[0].dataIndex);
    if(!Ext.isDefined(config.autoExpandColumn)&&!Ext.isDefined(config.columns[config.columns.length-1].width)) {
        config.autoExpandColumn = 'ys_action';
    }
    config.columns[config.columns.length-1].id = config.columns[config.columns.length-1].id || 'ys_action';
    var isSelectCheck = false;
    var smIndex=-1; //针对sm，进行重排
    
    //rows sort
    config.sortable = true;
    Ext.each(config.columns,function(item,i){
        item.sortable = false;
        item.menuDisabled = true;
        if(item=='sm'){
            //config.columns[i] = config.sm;
            smIndex = i;
            isSelectCheck = true;
        } else if(item.sort){
            item.sortable = true;
        };
    });

    if(smIndex != -1)
        config.columns.splice(smIndex,1);

    if(!Ext.isDefined(config.menuDisabled)){
        config.menuDisabled = true;
    }

    //init expand and collapse columns;
    var toggleColumns = [];
    var hasMoveColumn = false,hasSortColumn = false;
    Ext.each(config.columns, function(col){
        if(col.toggle) {
            col.hidden = true;
            toggleColumns.push(col.dataIndex);
        }
        if(col.xtype=='movecolumn' && !col.hidden) hasMoveColumn = true;
        else if(col.xtype=='sortcolumn' && !col.hidden) {
            hasSortColumn = true;
            col.grid = grid;
        }
    });
    if(toggleColumns.length > 0) {
        var detailBar = {
            text:Ext.langs.showColumns,
            enableToggle: true,
            pressed:true,
            cls:'btn-show',
            toggleHandler:function(btn,status) {
                grid.body.mask(Ext.langs.loading,'x-mask-loading');
                Ext.each(toggleColumns,function(item,i){
                    var cm = grid.getColumnModel();
                    var col = cm.findColumnIndex(item);
                    if(col!=-1) {
                        cm.setHidden(col,status);
                    }
                });
                if(status) {
                    btn.setText(Ext.langs.showColumns);
                } else {
                    btn.setText(Ext.langs.hideColumns);
                }
                grid.body.unmask();
                /*filter header re layout*/
                var fps = grid.grid.$this.filterPanels;
                if(fps) {
                    Ext.each(fps,function(item,i){
                        item.doLayout();
                    });
                }
            }
        };
    }

    //add move column handler
    //saveSortCfg:{params,name,dataIndex,url,hidden,canSaveFn}
    if(hasMoveColumn) {
        var btnSaveSortId = config.saveSortCfg.id || ('btn-sort-'+Ext.id());
        config.tbar = (config.tbar || []).concat(['-',{
            text:Ext.langs.sortSave,
            cls:'btn-show',
            id:btnSaveSortId,
            disabled:true,
            hidden:config.saveSortCfg.hidden,
            handler:config.saveSortCfg.handler || function() {
                var records = grid.getStore().getRange();
                var params = config.saveSortCfg.params || {};
                var it = 0;
                Ext.each(records,function(r,i) {
                    if(!Ext.isDefined( config.saveSortCfg.canSaveFn) || config.saveSortCfg.canSaveFn(r)) {
                        params[config.saveSortCfg.name+'['+(it++)+']'] = r.json[config.saveSortCfg.dataIndex];
                    }
                });
                ZM.ajax({
                    url:config.saveSortCfg.url,
                    params:params,
                    success:function(res) {
                        ZM.bo.msg('Success',res.detail);
                        grid.store.reload();
                        Ext.getCmp(btnSaveSortId).disable();
                    },
                    failure:function(res) {
                        ZM.bo.msg('Failure',res.detail);
                    }
                });
            }
        }]);
        grid.moveFirst =function(r) {
            ZM.moveSelectedRow(this,-2,r);
            Ext.getCmp(btnSaveSortId).enable();
        }
        grid.movePrevious =function(r) {
            ZM.moveSelectedRow(this,-1,r);
            Ext.getCmp(btnSaveSortId).enable();
        }
        grid.moveNext =function(r) {
            ZM.moveSelectedRow(this,1,r);
            Ext.getCmp(btnSaveSortId).enable();
        }
        grid.moveLast =function(r) {
            ZM.moveSelectedRow(this,2,r);
            Ext.getCmp(btnSaveSortId).enable();
        }
    }

    if(hasSortColumn) {
        config.listeners = Ext.applyIf(config.listeners||{},{'beforeedit':function(e){
            grid.rowNumber = e.row;
        }});
    }

    config.colModel = new Ext.grid.ColumnModel({
        defaults: {
            sortable: config.sortable,
            menuDisabled: config.menuDisabled
        },
        columns: config.columns
    })

    //////
    if(config.fields == null){
        config.fields = [];
        Ext.each(config.columns, function(item) {
            config.fields.push({name:item.dataIndex});
        });
    }

    if(config.group){
        config.store = new Ext.data.GroupingStore({
            reader:new Ext.data.JsonReader({
                totalProperty:'totalCount',
                root:'items',
                fields:config.fields
            }),
            listeners:{
                'loadexception' : function(v,o){
                    try {
                        Ext.Msg.alert(Ext.langs.error, o.reader.jsonData.detail||Ext.langs.loadTimeout);
                    }catch (e){
                        //Ext.Msg.alert('加载失败',e);
                    }

                }
            },
            proxy:new Ext.data.HttpProxy({url:config.url,timeout:config.timeout}),
            groupField:config.group.field,
            //remoteGroup:true,
            remoteSort:config.remoteSort,
            sortInfo:{field:config.group.field, direction:config.group.dir||'DESC'}
        });

        //if(config.group.groupView){
            config.view = new Ext.grid.GroupingView({
                emptyText: '<p class="red" align="center">'+Ext.langs.noData+'</p>',
                groupTextTpl: config.group.tpl||'{group}'//{text}
            });
        //}

    }else{
        config.store = new ZM.JsonStore({url:config.url,timeout:config.timeout,fields: config.fields,remoteSort:config.remoteSort});
    }
    config.store.baseParams = config.params||{}; /*初始化数据参数*/

    
    if(isSelectCheck)
        config.columns.unshift(config.sm);
    if(!config.noRowNumber)
        config.columns.unshift(new Ext.grid.RowNumberer());
    //////
    var view = {
        emptyText: '<p class="red" align="center">'+Ext.langs.noData+'</p>',
        scrollOffset: 20,
        //forceFit:config.autoExpandColumn?true:false,
        templates: {
            cell: new Ext.Template(
                '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} x-selectable {css}" style="{style}" tabIndex="0" {cellAttr}>',
                '<div class="x-grid3-cell-inner x-grid3-col-{id}" {attr}>{value}</div>',
                '</td>'
            )
        },
        getRowClass : function(record, rowIndex, p, ds){
            try{
                if(Ext.historyRecord && Ext.historyRecord.id==record.id && Ext.historyRecord.data[config.history] 
                    && Ext.historyRecord.data[config.history] == record.data[config.history]){
                    return ' grid-now';
                }
            }catch(e){}
        }
    }

    //行扩展收缩
    plugins = [new ZM.HeaderForm, new ZM.RowAction] ;
    items = [];
    detailBar && items.splice(items.length-1,0,'-',detailBar);
    Ext.apply(view,config.viewConfig);
    Ext.applyIf(config,{
        loadMask:true,
        loadMask: {msg: Ext.langs.loading},
        border:false,
        stateful:false,
        stripeRows:true,
        disableSelection:false,
        minColumnWidth : 60,
        //ajaxSubmit:true,
        //sm:sm,
        grid:this,
        remoteFilter:true,
        plugins: plugins,
        autoExpandMin:150,
        enableColumnMove:false,
        bbar: config.noPageBar?items:(new Ext.PagingToolbar({
            store:config.store,
            pageSize: config.pageSize || 20,
            displayInfo: true,
            displayMsg: '{0} - {1} '+Ext.langs.total+':<font class="b">{2}</font> ',
            emptyMsg: Ext.langs.noData,
            plugins:[new Ext.ux.PageSizePlugin({
                pageOptions: config.pageOptions
            })],
            items:items
        })),
        viewConfig: view
    });

    return config;
}
//GridPanel

//plugin for HeaderForm


ZM.GridPanel = function(config) {
    fixconfig(config,this);
    ZM.GridPanel.superclass.constructor.call(this, config);
};

Ext.extend(ZM.GridPanel, Ext.grid.GridPanel);


ZM.autoComplete = function(config) {
    var config = config || {};
    Ext.applyIf(config,{
        store: config.options||new ZM.JsonStore({url: config.url,autoLoad:true,fields: ['key','value']}),
        displayField:'value',
        valueField:'key',
        triggerAction: 'all',
        mode: 'local',
        emptyText:Ext.langs.select,
        forceSelection:true,
        hiddenName:config.name||'',
        selectOnFocus:true
    });
    ZM.autoComplete.superclass.constructor.call(this, config);
};

Ext.extend(ZM.autoComplete, Ext.form.ComboBox);
Ext.reg('autocomplete', ZM.autoComplete);



Ext.WindowGroup = function(){
    var list = {};
    var accessList = [];
    var front = null;

    // private
    var sortWindows = function(d1, d2){
        return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
    };

    // private
    var orderWindows = function(){
        var a = accessList, len = a.length;
        if(len > 0){
            a.sort(sortWindows);
            var seed = a[0].manager.zseed;
            for(var i = 0; i < len; i++){
                var win = a[i];
                if(win && !win.hidden){
                    try{
                        if(win.items.items.length==0)
                            seed += 10000;
                    }catch(e){}
                    win.setZIndex(seed + (i*10));
                }
            }
        }
        activateLast();
    };

    // private
    var setActiveWin = function(win){
        if(win != front){
            if(front){
                front.setActive(false);
            }
            front = win;
            if(win){
                win.setActive(true);
            }
        }
    };

    // private
    var activateLast = function(){
        for(var i = accessList.length-1; i >=0; --i) {
            if(!accessList[i].hidden){
                setActiveWin(accessList[i]);
                return;
            }
        }
        // none to activate
        setActiveWin(null);
    };

    return {
        zseed : 9000,
        register : function(win){
            if(win.manager){
                win.manager.unregister(win);
            }
            win.manager = this;

            list[win.id] = win;
            accessList.push(win);
            win.on('hide', activateLast);
        },
        unregister : function(win){
            delete win.manager;
            delete list[win.id];
            win.un('hide', activateLast);
            accessList.remove(win);
        },
        get : function(id){
            return typeof id == "object" ? id : list[id];
        },
        bringToFront : function(win){
            win = this.get(win);
            if(win != front){
                win._lastAccess = new Date().getTime();
                orderWindows();
                return true;
            }
            return false;
        },
        sendToBack : function(win){
            win = this.get(win);
            win._lastAccess = -(new Date().getTime());
            orderWindows();
            return win;
        },
        hideAll : function(){
            for(var id in list){
                if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
                    list[id].hide();
                }
            }
        },
        getActive : function(){
            return front;
        },
        getBy : function(fn, scope){
            var r = [];
            for(var i = accessList.length-1; i >=0; --i) {
                var win = accessList[i];
                if(fn.call(scope||win, win) !== false){
                    r.push(win);
                }
            }
            return r;
        },
        each : function(fn, scope){
            for(var id in list){
                if(list[id] && typeof list[id] != "function"){
                    if(fn.call(scope || list[id], list[id]) === false){
                        return;
                    }
                }
            }
        }
    };
};
Ext.WindowMgr = new Ext.WindowGroup();

//EditorGridPanel
ZM.EditorGridPanel = function(config) {
    fixconfig(config,this);
    config.clicksToEdit = 1;
    ZM.EditorGridPanel.superclass.constructor.call(this, config);
};
Ext.extend(ZM.EditorGridPanel, Ext.grid.EditorGridPanel);



ZM.GroupPanel = function(config) {
    var config = config || {};

    Ext.applyIf(config,{
        trackMouseOver:false,
        grid:this,
        plugins:[new ZM.HeaderForm, config.expander, new ZM.RowAction],

        bbar: new Ext.PagingToolbar({
            store:config.store,
            pageSize: config.pageSize||20,
            displayInfo: true,
            displayMsg: '{0} - {1} '+Ext.langs.total+':<font class="b">{2}</font> ',
            emptyMsg: Ext.langs.noData,
            items:['-',{text: Ext.langs.collapseAll,ctCls:'ZM-btn', handler: function(btn, pressed){config.expander.collapseAll()}},
                '',{text: Ext.langs.expandAll,ctCls:'ZM-btn', handler: function(btn, pressed){config.expander.expandAll()}}],
            plugins:[new Ext.ux.PageSizePlugin({
                pageOptions: config.pageOptions
            })]
        })
    });
    // call the superclass's constructor 
    ZM.GroupPanel.superclass.constructor.call(this, config);
};
Ext.extend(ZM.GroupPanel, ZM.GridPanel);
Ext.reg('gridpanel', ZM.GridPanel);
Ext.reg('editorgridpanel', ZM.EditorGridPanel);
Ext.reg('grouppanel', ZM.GroupPanel);

////////////////////////
ZM.Combo = Ext.extend(Ext.form.ComboBox, {
    initComponent: function() {
        if(this.type&&this.type=='lang'){
            this.tpl = '<tpl for="."><div class="x-combo-list-item x-icon-combo-item x-flag-{field1}">{field2}</div></tpl>';
            this.on({
                render:{scope:this, fn:function() {
                    this.el.addClass('x-icon-combo-input x-flag-'+this.value);
                }}
            });
        }
        
        Ext.apply(this, {
            store:new Ext.data.SimpleStore({
                fields: ['value', 'text'],
                data: this.options
            }),
            //typeAhead: true,
            editable:false,
            mode: 'local',
            forceSelection: true,
            triggerAction: 'all',
            value:this.value||'',
            emptyText:this.emptyText||Ext.langs.pleseChoose,
            valueField: 'value',
            displayField: 'text',
            //lazyRender:true,
            hiddenName:this.name
            //selectOnFocus:true
        });

        if(this.autoComplete){
            this.editable = true;
            this.triggerAction = 'all';
        }
        ZM.Combo.superclass.initComponent.call(this);
    },
    onSelect : function(record, index){
        if(this.fireEvent('beforeselect', this, record, index) !== false){
            var v = record.data[this.valueField || this.displayField];
            this.setValue(v);
            this.collapse();
            
            if(this.targetid&&this.targetoptions){
                var opts = [];
                if(v==''){
                    for(var op in this.targetoptions){
                        opts = opts.concat(this.targetoptions[op]);
                    }
                    opts.unique();
                }else{
                    opts = this.targetoptions[v];
                }
                Ext.getCmp(this.targetid).updateOptions(opts);
                Ext.getCmp(this.targetid).setValue('');
            }

            this.fireEvent('select', this, record, index);
        }
    },
    //yy添加的更新options2012-10-26
    updateOptions:function(options){
        if(!Ext.isDefined(options)){
            options=[];
        }
        this.bindStore(new Ext.data.SimpleStore({
            fields: ['value', 'text'],
            data: options
        }));
    }
});
Ext.reg('combofield', ZM.Combo);

ZM.DatetimeField = Ext.extend(Ext.form.TriggerField, {

    expanded: false,
    triggerClass:'x-form-pop-trigger',
    datepicker:{xtype:'datepicker',format:'y-M-d'},
    timepicker:{xtype:'timefield',width:130,fieldLabel: Ext.langs.time,format:'H:i:s'},

    initComponent:function() {
        ZM.DatetimeField.superclass.initComponent.call(this);
        this.datepicker = new Ext.DatePicker(this.datepicker);
        this.timepicker = new Ext.form.TimeField(this.timepicker);
        //this.readOnly = true;
        this.popup = new Ext.Layer(
            {
                constrain: false,
                shadow: true
            });

        var elPanel = this.popup.createChild();
        new Ext.Panel({
            renderTo: elPanel,
            layout: "form",
            bodyStyle:"padding:10px 20px 10px 10px",
            width:240,
            labelWidth:40,
            items: [
                this.datepicker,
                {xtype:'displayfield',style:'padding:5px'},
                this.timepicker,
                {
                    layout: 'table',
                    border: false,
                    layoutConfig: {
                        columns: 2
                    },
                    items:[
                        {xtype: "button", text: Ext.langs.confirm, listeners: {"click": {fn: this.confirm, scope: this}}},
                        {xtype: "button", text: Ext.langs.cancel, style:'margin-left:5px', listeners: {"click": {fn: this.cancel, scope: this}}}
                    ]
                }]
        });

        this.addEvents("confirm");
    },

    onRender: function(ct, position)
    {
        ZM.DatetimeField.superclass.onRender.call(this, ct, position);
    },

    onTriggerClick : function(e){
        (this.expanded)?this.confirm():this.expand();
        if(this.expanded) {
            var timeArray = this.getValue().split(" ");
            if( timeArray.length == 2 ){
                if(timeArray[0]!='0000-00-00') this.datepicker.setValue( ZM.parseDate(timeArray[0]));
                this.timepicker.setRawValue(timeArray[1]);
            }
        }
        ZM.DatetimeField.superclass.onTriggerClick.call(this,e);

    },

    confirm: function()
    {
        var dv = this.datepicker.getValue(),
            tv = this.timepicker.getRawValue();
        this.setValue(dv.format('yyyy-MM-dd')+' '+(tv || '00:00:00'));
        this.collapse();
        this.focus();
    },

    expand: function()
    {
        if(this.expanded || this.disabled)
            return;
        this.popup.alignTo(this.el, "tl-bl?");
        this.popup.show();
        this.expanded = true;
    },

    cancel:function()
    {
        this.collapse();
        this.focus();
    },

    collapse: function()
    {
        if(!this.expanded)
        {
            return;
        }
        this.popup.hide();
        this.expanded = false;
    }
});
Ext.reg('datetimefield', ZM.DatetimeField);


ZM.RadioGroup = Ext.extend(Ext.form.RadioGroup, {
    columns:2,
    initComponent: function() {
        var items = [],name=this.name, v=this.value||'';
        Ext.each(this.options,function(item){
            items.push({'boxLabel':item[1],'inputValue':item[0],'name':name,'checked':!(item[0]!=v)})
        });
        Ext.applyIf(this, {
            items:items
        });
        ZM.RadioGroup.superclass.initComponent.call(this);
    }
});
Ext.reg('radiogroupfield', ZM.RadioGroup);

ZM.CheckboxGroup = Ext.extend(Ext.form.CheckboxGroup, {
    columns:2,
    initComponent: function() {
        var items = [],name=this.name, v=this.value||[];
        this.value = undefined;
        Ext.each(this.options,function(item){
            items.push({'boxLabel':item[1],'inputValue':item[0],'name':name,'checked':v.indexOf(item[0])>-1})
        })
        Ext.applyIf(this, {
            items:items
        });
        ZM.CheckboxGroup.superclass.initComponent.call(this);
    }
});
Ext.reg('checkboxgroupfield', ZM.CheckboxGroup);

ZM.ClearField = Ext.extend(Ext.form.TriggerField, {
    initComponent : function(){
        ZM.ClearField.superclass.initComponent.call(this);

    },
    triggerClass:'x-form-clear-trigger',
    onTriggerClick : function(e){
        ZM.ClearField.superclass.onTriggerClick.call(this,e);
        this.setValue('');
        this.focus(false,500)
    }
});
Ext.reg('clearfield', ZM.ClearField);


ZM.TextRangeField = Ext.extend(Ext.form.TriggerField, {
    startField:{fieldLabel:Ext.langs.from, xtype:'textfield'},
    endField:{fieldLabel:Ext.langs.to, xtype:'textfield'},
    expanded: false,
    triggerClass:'x-form-pop-trigger',
    delimiter:'|',

    initComponent:function() {
        ZM.TextRangeField.superclass.initComponent.call(this);
        this.startField.id = Ext.id();
        this.endField.id = Ext.id();
        /*if(this.startField.xtype=='datefield'&&this.endField.xtype=='datefield'){
         this.startField.name = this.endField.startDateField = this.startField.id;
         this.endField.name = this.startField.endDateField = this.endField.id;
         this.startField.vtype = this.endField.vtype = 'daterange';
         }*/
        this.readOnly = true;
        this.popup = new Ext.Layer(
            {
                constrain: false,
                shadow: true
            });

        var elPanel = this.popup.createChild();
        new Ext.Panel({
            renderTo: elPanel,
            layout: "form",
            bodyStyle:"padding:10px 20px 10px 10px",
            width:180,
            labelWidth: 15,
            defaults: {width: 125},
            items: [
                this.startField,
                this.endField,
                {
                    layout: 'table',
                    border: false,
                    layoutConfig: {
                        columns: 2
                    },
                    items:[
                        {xtype: "button", text: Ext.langs.confirm, listeners: {"click": {fn: this.confirm, scope: this}}},
                        {xtype: "button", text: Ext.langs.cancel,style:'margin-left:5px', listeners: {"click": {fn: this.cancel, scope: this}}}
                    ]
                }]
        });

        this.addEvents("confirm");
        this.addEvents("cancel");
    },

    onRender: function(ct, position)
    {
        ZM.TextRangeField.superclass.onRender.call(this, ct, position);
    },

    onTriggerClick : function(e){
        var timeArray = this.getValue().split(this.delimiter);
        if( timeArray.length == 2 ){
            Ext.getCmp(this.startField.id).setValue(timeArray[0]);
            Ext.getCmp(this.endField.id).setValue(timeArray[1]);
        }
        ZM.TextRangeField.superclass.onTriggerClick.call(this,e);
        (this.expanded)?this.confirm():this.expand();
    },

    confirm: function()
    {
        if(!this.isValid())
            return;
        this.setValue(Ext.getCmp(this.startField.id).getRawValue()+this.delimiter+Ext.getCmp(this.endField.id).getRawValue());
        this.collapse();
        this.focus();
        this.fireEvent('confirm', this);
    },

    expand: function()
    {
        if(this.expanded || this.disabled)
            return;
        this.popup.alignTo(this.el, "tl-bl?");
        this.popup.show();
        this.expanded = true;
    },

    cancel:function()
    {
        this.collapse();
        this.setValue('');
        this.focus();
        this.fireEvent('cancel', this);
    },

    collapse: function()
    {
        if(!this.expanded)
        {
            return;
        }
        this.popup.hide();
        this.expanded = false;
    },

    isValid: function()
    {
        if(Ext.getCmp(this.startField.id).isValid()&&Ext.getCmp(this.endField.id).isValid())
            return true;
        return false;
    }

});
Ext.reg('textrangefield', ZM.TextRangeField);

ZM.FloatRangeField = Ext.extend(ZM.TextRangeField, {
    startFieldLabel:Ext.langs.from,
    endFieldLabel:Ext.langs.to,
    delimiter:'~',
    allowNegative:false,
    initComponent: function() {
        Ext.apply(this, {
            startField:{xtype:'numberfield',fieldLabel:this.startFieldLabel,allowNegative: this.allowNegative},
            endField:{xtype:'numberfield',fieldLabel:this.endFieldLabel,allowNegative: this.allowNegative}
        });
        ZM.FloatRangeField.superclass.initComponent.call(this);
    }
});
Ext.reg('floatrangefield', ZM.FloatRangeField);

ZM.DateRangeField = Ext.extend(ZM.TextRangeField, {
    disabledDays: [],
    delimiter:'~',
    initComponent: function() {
        Ext.apply(this, {
            startField:{xtype:'datefield',fieldLabel:Ext.langs.from,format:'Y-m-d',disabledDays:this.disabledDays },
            endField:{xtype:'datefield',fieldLabel:Ext.langs.to,format:'Y-m-d',disabledDays:this.disabledDays}
        });
        ZM.DateRangeField.superclass.initComponent.call(this);
    }
});
Ext.reg('daterangefield', ZM.DateRangeField);

ZM.DateTimeRangeField = Ext.extend(ZM.TextRangeField, {
    disabledDays: [],
    delimiter:'~',
    initComponent: function() {
        Ext.apply(this, {
            startField:{xtype:'datetimefield',fieldLabel:Ext.langs.from,disabledDays:this.disabledDays },
            endField:{xtype:'datetimefield',fieldLabel:Ext.langs.to,disabledDays:this.disabledDays}
        });
        ZM.DateTimeRangeField.superclass.initComponent.call(this);
    }
});
Ext.reg('datetimerangefield', ZM.DateTimeRangeField);

Ext.override(Ext.form.DateField, {
    diffTime : 0,
    setValue : function(date){
        try{
            date = new Date(date.getTime()+this.diffTime);
        }catch(e){}
        return Ext.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
    },
    beforeBlur : Ext.emptyFn
});


ZM.ComboFields = Ext.extend(Ext.form.TriggerField, {

    multiField:{xtype:'checkboxgroupfield'},
    expanded: false,
    triggerClass:'x-form-pop-trigger',
    submitValue:false,

    initComponent:function() {
        ZM.ComboFields.superclass.initComponent.call(this);

        this.multiField.id = this.id + '_lay';
        this.multiField.height = Number(this.listHeight)||'auto';
        this.multiField.columns = 1;

        this.multiField.options = this.options;
        this.multiField.value = this.value;

        this.readOnly = true;
        this.popup = new Ext.Layer(
            {
                constrain: false,
                shadow: true
            });

        var elPanel = this.popup.createChild();
        new Ext.Panel({
            renderTo: elPanel,
            layout: "form",
            bodyStyle:"padding:10px",
            width:180,
            labelWidth: 15,
            defaults: {width: 125},
            items: [
                this.multiField,
                {
                    layout: 'table',
                    border: false,
                    layoutConfig: {
                        columns: 2
                    },
                    items:[
                        {xtype: "button", text: Ext.langs.confirm, listeners: {"click": {fn: this.confirm, scope: this}}},
                        {xtype: "button", text: Ext.langs.cancel,style:'margin-left:5px', listeners: {"click": {fn: this.cancel, scope: this}}}
                    ]
                }]
        });
        this.addEvents("confirm");
        this.addEvents("cancel");
    },

    onRender: function(ct, position)
    {
        ZM.ComboFields.superclass.onRender.call(this, ct, position);
    },
    onDestroy : function(){
        Ext.destroy(this.popup);
        ZM.ComboFields.superclass.onDestroy.call(this);
    },
    onTriggerClick : function(e){
        ZM.ComboFields.superclass.onTriggerClick.call(this,e);
        (this.expanded)?this.cancel():this.expand();
    },
    confirm: function()
    {
        if(!this.isValid())
            return;

        this.setValue(this.getValue());
        this.collapse();
        this.focus();
        this.fireEvent('confirm', this);
    },
    getValue:function() {
        var val = [];
        Ext.each(Ext.getCmp(this.id + '_lay').getValue(),function(cb,i){
            val.push(cb.getRawValue());
        });
        return val;
    },
    setValue:function(values) {
        var v = [];
        var me = this;
        if(values) {
            Ext.each(values,function(val,i){
                v.push(ZM.id2name(val,me.options));
            });
        }
        this.value = v;
        this.el.dom.value = this.value.join(',');
        return this;
    },
    expand: function()
    {
        if(this.expanded || this.disabled)
            return;
        this.popup.alignTo(this.el, "tl-bl?");
        this.popup.show();
        this.expanded = true;
    },

    cancel:function()
    {
        this.collapse();
        //this.setValue(this.displayValue);
        Ext.getCmp(this.id + '_lay').reset();
        this.setValue('');
        this.focus();
        this.fireEvent('cancel', this);
    },

    collapse: function()
    {
        if(!this.expanded)
        {
            return;
        }
        this.popup.hide();
        this.expanded = false;
    },

    isValid: function()
    {
        if(Ext.getCmp(this.id + '_lay').isValid())
            return true;
        return false;
    }

});
Ext.reg('combofields', ZM.ComboFields);
/*-------windows---------*/
//用来解决是否Ajax提交表单_eof
ZM.PopUp = function(config) {
    var config = config || {};
    switch(config.type)
    {
        case 's':
            config.width = config.width||365;
            config.height = config.height||215;
            break;
        case 'l':
            config.width = config.width||950;
            config.height = config.height||600;
            break;
        default:
            config.width = config.width||525;
            config.height = config.height||455;
    }
    config.height = Math.min(Ext.getBody().getViewSize().height-20,config.height);
    config.width = Math.min(Ext.getBody().getViewSize().width*0.8,config.width);

    Ext.applyIf(config,{
        title:Ext.langs.window,
        layout:'fit',
        constrain:true,
        plain : true,
        resizable: false,
        //maximizable: true,
        modal : true,
        //bodyStyle:'background:#DFE8F6;padding:10px;',
        autoScroll:true
    });
    // call the superclass's constructor 
    ZM.PopUp.superclass.constructor.call(this, config);
};
Ext.extend(ZM.PopUp, Ext.Window);

ZM.Pop = function operateOrder(config){
    var config = config || {};
    Ext.applyIf(config,{
        url:'',
        allowBlank:true,
        title : 'ADD CONMENTS',
        params : {},
        success : function(){}
    });

    var fs = {xtype: 'textarea',allowBlank:config.allowBlank};
    var win = new ZM.PopUp({type:'s',tbar:[
        {
            text    : Ext.langs.save,
            iconCls : 'icon-save',
            ctCls   : 'x-btn-over',
            handler : function(){
                var el = win.items.items[0];
                if(!el.validate()){
                    return;
                }
                var text = el.getValue();
                config.params[config.popName] = text;

                ZM.ajax({
                    url: config.url,
                    success:function(r){
                        Ext.Msg.alert(Ext.langs.success, r.detail, function(){config.success(); win.hide();});
                    },
                    params: config.params
                });
            }
        }
    ],title:config.title,items:fs}).show();
}

//用来解决是否Ajax提交表单_bof
Ext.override(Ext.form.BasicForm, {
    initEl : function(el){
        this.el = Ext.get(el);
        this.id = this.el.id || Ext.id();
        if (!(this.ajaxSubmit == false)) {
            this.el.on('submit', this.onSubmit, this);
        }
        this.el.addClass('x-form');
    },
    lastOptions:{},
    submit : function(options){
        this.lastOptions = {};
        this.items.each(function(f){
            this.lastOptions[f.getName()]=f.getValue();
            if(f.emptyText&&f.getValue()==='') {
                f.el.dom.value = '';
            }
        },this);

        if (this.ajaxSubmit == false) {
            this.el.dom.action = this.url;
            this.el.dom.submit();
        } else {
            this.doAction('submit', options);
        }
        return this;
    }
});
//用来解决是否Ajax提交表单_eof

ZM.keyForm = function(config){
    Ext.apply(this, config);
    ZM.keyForm.superclass.constructor.call(this);
};

Ext.extend(ZM.keyForm, Ext.util.Observable, {
    init : function(fs){
        fs.on('afterrender', function(){
            new Ext.KeyNav(fs.getForm().getEl(), {
                'enter': function(e,b,c) {
                    //文字输入框回车不提交表单
                    //if(e.getTarget().tagName != 'TEXTAREA')
                    if(!fs.enterKeyTraverse) {
                        if(fs.submitForm) {
                         fs.submitForm(fs)
                        } else {
                            ZM.submitForm(fs);
                        }
                    }
                },
                'scope': fs
            })
        }, this);
    }
});
/*form first field focus*/
ZM.focusField = function(config){
    Ext.apply(this, config);
    ZM.focusField.superclass.constructor.call(this);
};
Ext.extend(ZM.focusField, Ext.util.Observable, {
    init : function(fs){
        fs.on('afterrender', function(){
            fs.items.each(function(f){
                if((f.xtype=='textfield'||f.xtype=='textarea')&&(!fs.focusName || fs.focusName== f.name)){
                    f.on('afterrender',function(){setTimeout(function(){f.focus(true);},500);});
                    return false;
                }
            });
        }, this);
    }
});

/*form field enty key traverse(tabindex)*/
ZM.enterKeyTraverse = function(config) {
    Ext.apply(this, config);
    ZM.enterKeyTraverse.superclass.constructor.call(this);
};
Ext.extend(ZM.enterKeyTraverse, Ext.util.Observable, {
    init : function(fs){
        //console.log(fs.items);
        fs.on('afterrender', function(){
            fs.items.each(function(f,i){
                f.tabIndex = i+1;
                f.on('specialkey',function(field, e){
                    if (e.getKey() == e.ENTER && field.validate()) {
                        var index =field.tabIndex,
                            nf = fs.items.get(index);
                        if((nf && nf.xtype=='button') || index == fs.items.getCount()) {
                            if(fs.submitForm) {
                                fs.submitForm(fs)
                            } else {
                                ZM.submitForm(fs);
                            }
                        } else {
                            nf.focus(true)
                        }
                    }
                },f);
            })
        });
    }
});

ZM.FormPanel = function(config) {
    var config = config || {};
    var plugins = [];
    Ext.applyIf(config,{
        keySubmit:false,
        focusField:false,
        enterKeyTraverse:false
    });
    if(config.keySubmit) {
        plugins.push(new ZM.keyForm());
    }
    if(config.focusField) {
        plugins.push(new ZM.focusField());
    }
    if(config.enterKeyTraverse) {
        plugins.push(new ZM.enterKeyTraverse());
    }
    config.items = config.items || [];
    Ext.applyIf(config,{
        labelWidth:85,
        labelAlign:'right',
        border:false,
        id:Ext.id(),
        buttons:[{text:Ext.langs.submit,handler:function(){
            ZM.submitForm(Ext.getCmp(config.id));
        }}],
        bodyStyle:'padding:10px;',
        waitMsgTarget: true,
        plugins:plugins,
        defaults:{xtype: 'textfield',width:220,listeners: {
                                   blur : function(){
                                        this.getValue() && this.getValue().trim && this.setValue(this.getValue().trim());
                                    }
                                }},
        bodyStyle:'padding-top:15px;background-color:#DDD',/*#DFE8F6*/
        autoScroll:true
    });
    if(config.onlyShow) {
        config.defaults.xtype = 'displayfield';
        config.defaults.disabled = true;
        config.buttons = null;
    }
    //just for temp
    config.url = config.url;
    config.isChanged = function(){
        var changed = false;
        this.form.items.each(function(item) {
            try{
                if(Ext.isDefined(item.value)){
                    if(item.originalValue!=item.getValue())
                        changed = true;
                }
            }catch(e){}
        });
        return changed;
    }
    ZM.FormPanel.superclass.constructor.call(this, config);
};
Ext.extend(ZM.FormPanel, Ext.form.FormPanel);
Ext.reg('formpanel', ZM.FormPanel);

//int型xtype
ZM.IntField = function(config) {
    var config = config || {};
    Ext.applyIf(config,{
        minValue: 1,
        maxValue: 2147483647,
        allowDecimals:false,
        allowNegative:false
    });
    // call the superclass's constructor 
    ZM.IntField.superclass.constructor.call(this, config);
};
Ext.extend(ZM.IntField, Ext.form.NumberField);
Ext.reg('intfield', ZM.IntField);

//重写tree,显示状态样式
Ext.tree.TreeLoader.prototype.createNode = function(attr){
    var nodeBaseAttribute = {};
    //nodeBaseAttribute.iconCls = "cates";
    if( attr.objects_status_id != undefined && attr.objects_status_id==0){
        nodeBaseAttribute.cls = 'gray';
    }
    Ext.applyIf(attr, nodeBaseAttribute);
    // apply baseAttrs, nice idea Corey!
    if(this.baseAttrs){
        Ext.applyIf(attr, this.baseAttrs);
    }
    if(this.applyLoader !== false){
        attr.loader = this;
    }
    if(typeof attr.uiProvider == 'string'){
        attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider);
    }
    if(attr.nodeType){
        return new Ext.tree.TreePanel.nodeTypes[attr.nodeType](attr);
    }else{
        return attr.leaf ?
            new Ext.tree.TreeNode(attr) :
            new Ext.tree.AsyncTreeNode(attr);
    }
};

//树过滤工具
ZM.TreeFilterX = Ext.extend(Ext.tree.TreeFilter, {
    filter:function(value, attr, startNode) {
        startNode = startNode || this.tree.root;

        var animate = this.tree.animate;
        this.tree.animate = false;

        startNode.expand(true, false, function() {
            // call parent after expand
            ZM.TreeFilterX.superclass.filter.call(this, value, attr, startNode);
        }.createDelegate(this));
        this.tree.animate = animate;
    } // eo function filter

    ,filterBy:function(fn, scope, startNode) {
        startNode = startNode || this.tree.root;
        if(this.autoClear) {
            this.clear();
        }
        var af = this.filtered, rv = this.reverse;

        var f = function(n) {
            if(n === startNode) {
                return true;
            }
            if(af[n.id]) {
                return false;
            }
            var m = fn.call(scope || n, n);
            if(!m || rv) {
                af[n.id] = n;
                n.ui.hide();
                return true;
            }
            else {
                n.ui.show();
                var p = n.parentNode;
                while(p && p !== this.root) {
                    p.ui.show();
                    p = p.parentNode;
                }
                return true;
            }
            return true;
        };
        startNode.cascade(f);

    } // eo function filterBy
    // }}}

}); // eo extend
// eof

//左边分类树菜单   
ZM.treeNav = function(config) {

    var config = config || {};
    tree = this;

    Ext.applyIf(config,{
        frame:true,
        collapsible:true,
        titleCollapse: true,
        border:false,
        title:Ext.langs.navCategory,
        filter:new ZM.TreeFilterX(tree),
        root:{
            nodeType:'async',
            id:'0',
            text:Ext.langs.allCategory,
            expanded:true
        },
        loader: new Ext.tree.TreeLoader({
            dataUrl:config.dataUrl||config.url||'cmsjsontree.json',
            dataRoot: config.dataRoot||'items'
        })
    });
    ZM.treeNav.superclass.constructor.call(this, config);
};
Ext.extend(ZM.treeNav, Ext.tree.TreePanel);
Ext.reg('treenav', ZM.treeNav);

ZM.TrigerTree = Ext.extend(Ext.form.TriggerField, {
    initComponent: function() {
        var hideField,tree,win
        var field = this;
        this.hiddenName = this.name;

        field.values = [];
        field.ids = '';
        var loader = {};
        if(this.multi){
            loader = new Ext.tree.TreeLoader({
                baseAttrs:{checked:false},
                url: field.url
            })
        }else{
            loader = new Ext.tree.TreeLoader({
                url: field.url
            })
        }
        tree = new Ext.tree.TreePanel({
            autoScroll: true,
            //rootVisible: false,
            lines: false,
            singleExpand: (field.multi)?false:true,
            useArrows: true,
            rootVisible:(field.rootVisible)?true:false,
            root:{
                nodeType:'async',
                id:'0',
                text:Ext.langs.topCategory,
                expanded:true,
                defaultChecked:true
            },
            loader:loader
        });

        if(!this.multi){
            tree.getSelectionModel().on('selectionchange', function(node){
                field.values[0] = {id:node.selNode.id, value:node.selNode.text}
            });
        }

        Ext.apply(this, {
            triggerClass:'x-form-pop-trigger',
            //triggerClass:'x-form-trigger',
            submitValue:false,
            name:'',
            onTriggerClick:function() {
                //
                field.values = [];
                if(!win){
                    win = new ZM.PopUp({
                        title:Ext.langs.chooseCategory,
                        closeAction :'hide',
                        border: false,
                        width:400,
                        tbar:[{
                            ctCls   : 'x-btn-over',
                            text    : Ext.langs.confirm,
                            iconCls :'icon-save',
                            handler : function(){
                                if(field.multi){
                                    selNodes = tree.getChecked();
                                    Ext.each(selNodes, function(node){
                                        field.values.push({id:node.attributes.id, value:node.attributes.text});
                                    });
                                }

                                if(field.values.length<1){
                                    Ext.Msg.alert(Ext.langs.failure,Ext.langs.chooseCategory);
                                    return;
                                }

                                var k = [];
                                var v = [];
                                Ext.each(field.values,function(item){
                                    k.push(item.id);
                                    v.push(item.value);
                                })

                                field.ids = k.join();


                                (field.showId)?field.setValue(k.join()):field.setValue(v.join());
                                field.hideField.dom.value = k.join();
                                win.hide();
                                field.focus();
                            }

                        }],

                        items : tree
                    });
                }
                win.show();
            }
        });
        ZM.TrigerTree.superclass.initComponent.call(this);
    },
    afterRender:function() {
        ZM.TrigerTree.superclass.afterRender.call(this);
        this.hideField = this.el.insertSibling(
            {tag:'input', type:'hidden', name: this.hiddenName}
        );

        if(this.showId)
            return;

        if(this.value){
            if(this.value=='0'){
                this.hideField.dom.value = 0;
                this.setValue(Ext.langs.topCategory);
                return;
            }
            if(Ext.isNumber(this.value))
                this.value = String(this.value);
            var arr = this.value.split(',');
            Ext.Ajax.request({
                url: this.url,
                success: function(r) {
                    var str = r.responseText;
                    var tarr = [];
                    Ext.each(arr,function(v){
                        var regex='/\"id\"\:\"{0,1}'+v+'\"{0,1},(.*?)\"text\"\:\"([^\"]+)\"/';
                        regex=eval(regex);
                        var a=regex.exec(str);
                        tarr.push(a[2]);
                    })

                    this.hideField.dom.value = this.value;
                    this.setValue(tarr.join());

                },
                scope:this
            });
        }
        //end of value is not null
    },
    getValue:function(){
        //ZM.TrigerTree.superclass.getValue.call(this);
        if(this.showId)
            return ZM.TrigerTree.superclass.getValue.call(this);
    }
});
Ext.reg('tree', ZM.TrigerTree);
//eof FormTree


ZM.bo = function(){
    var msgCt;

    function createBox(t, s){
        return ['<div class="msg x-box-blue">',
            '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
            '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc"><h3>', t, '</h3>', s, '</div></div></div>',
            '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
            '</div>'].join('');
    }
    return {
        msg : function(title, format){
            if(!msgCt){
                msgCt = Ext.DomHelper.insertFirst(document.body, {id:'msg-div'}, true);
            }
            msgCt.alignTo(document, 't-t');
            var s = String.format.apply(String, Array.prototype.slice.call(arguments, 1));
            var m = Ext.DomHelper.append(msgCt, {html:createBox(title, s)}, true);
            m.slideIn('t').pause(1).ghost("t", {remove:true});
        },

        init : function(){
            var lb = Ext.get('lib-bar');
            if(lb){
                lb.show();
            }
        }
    };
}();

Ext.onReady(ZM.bo.init, ZM.bo);


ZM.MapPanel = Ext.extend(Ext.Panel,{
    map:null,
    region:'center',
    latitude:39.916527, //初始数据纬度
    longitude:116.397128, //初始数据经度
    defaultLatitude:39.915, //默认数据纬度
    defaultLongitude:116.404, //默认数据经度
    attr:null, //中心点的属性
    editable:true,
    zoomLevel:18, //缩放级别
    url:'',//请求地址
    params:{},//请求参数
    icons:null,//对所有icon进行渲染
    iconDefaultWidth:20,
    iconDefaultHeight:25,
    afterDataLoad:Ext.emptyFn,
    //afterDrag:Ext.emptyFn,
    //afterLoaction:Ext.emptyFn,
    fields:['attr.id','attr.name'],
    fieldsTpl:'<dt>{0}</dt><dd>{1}</dd>',
    style:{'width':'100%', 'height':'100%'},    
    cls:'shop-info-view',
    markers : [],
    curLocation:null,
    infoWindow:null,
    //areaSelection:{}, //区域选择,{callback}
    afterRender : function(){
        ZM.MapPanel.superclass.afterRender.call(this);
        var me = this;
        this.id = this.id || Ext.id();
        me.map = new qq.maps.Map(this.id);
        me.checkLatLng(); //检测点
        // me.map.centerAndZoom(new BMap.Point(me.longitude, me.latitude), me.zoomLevel);
        me.map.setCenter(new qq.maps.LatLng(me.latitude, me.longitude));
        me.map.zoomTo(me.zoomLevel);
        me.infoWindow = new qq.maps.InfoWindow({
            map: me.map
        });
        // me.map.addControl(new BMap.NavigationControl());
        // me.map.addControl(new BMap.MapTypeControl({anchor: BMAP_ANCHOR_TOP_RIGHT}));
        // me.map.enableScrollWheelZoom(); //启用滚轮放大缩小
        
        //当配置url时，默认为移动，放大都刷新marker
        if(me.url!=''){
            if(me.allShowed) {
                me.getEl().mask(Ext.langs.loading,'x-mask-loading');
                me.updateMarkers();//调用ajax update markers;
            } else {
                qq.maps.event.addListener(me.map, 'tilesloaded',function(e){
                    me.getEl().mask(Ext.langs.loading,'x-mask-loading');
                    me.updateMarkers();//调用ajax update markers;
                });
            }
        } else {
            if(me.editable) {
                qq.maps.event.addListener(me.map, 'tilesloaded',function(e){
                    if(!me.defaultmarker) {
                        me.defaultmarker = me.addMarker(new qq.maps.LatLng(me.latitude , me.longitude),null,me.attr);
                        me.setCurLocation();
                        me.defaultmarker.setDraggable(true);
                        // me.defaultmarker.setTop(true);
                        qq.maps.event.addListener(me.defaultmarker, 'dragend', function() {
                            var point = me.defaultmarker.getPosition();
                            me.map.panTo(point);
                            me.longitude = point.getLng();
                            me.latitude = point.getLat();
                            me.setCurLocation();
                            me.afterDrag && me.afterDrag(me);
                        });
                    }
                });
            }
        }
        if(me.areaSelection) {
            var circleCfg = {
                points:[],
                status:0,
                distance:0
            }
            var circleOverlay = new qq.maps.Circle({
                map:me.map,
                center:new qq.maps.LatLng(0,0),
                radius:1,
                fillColor: new qq.maps.Color(0,15,255, 0.5),
                strokeColor: '#ff0',
                strokeWeight:3
            });
            var radiusOverlay = new qq.maps.Polyline({
                path: [],
                strokeColor: new qq.maps.Color(51,51,204, 0.5),
                strokeWeight: 3,
                map: me.map
            });
            var radiusInfoLabel = new qq.maps.Label({
                position: new qq.maps.LatLng(0,0),
                map: me.map,
                content:'文本标注'
            });

            radiusInfoLabel.setZIndex(1000);
            radiusInfoLabel.setStyle({"border":"none"});

            circleOverlay.setVisible(false);
            radiusOverlay.setVisible(false);
            radiusInfoLabel.setVisible(false);

            qq.maps.event.addListener(me.map,'click',function(params) {
                circleOverlay.setVisible(true);
                radiusOverlay.setVisible(true);
                radiusInfoLabel.setVisible(true);
                var point = params.latLng;
                if(circleCfg.status == 0) {
                    circleCfg.points = [point,new qq.maps.LatLng(point.getLat()+0.000001,point.getLng()+0.000001)];
                } else if(circleCfg.status == 1) {
                    circleCfg.points[1] = point;
                    circleCfg.distance = qq.maps.geometry.spherical.computeDistanceBetween(circleCfg.points[0],circleCfg.points[1]);
                    me.areaSelection.callback && me.areaSelection.callback(circleCfg,me);
                }
                circleCfg.status = 1 - circleCfg.status;
                drawLineCircle();
            });
            qq.maps.event.addListener(me.map,'mousemove',function(params) {
                if(circleCfg.status == 1) {
                    var point = params.latLng;
                    circleCfg.points[1] = point;
                    drawLineCircle();
                }
            });
            qq.maps.event.addListener(me.map,'rightclick',function(params) {
                circleOverlay.setVisible(false);
                radiusOverlay.setVisible(false);
                radiusInfoLabel.setVisible(false);
                circleCfg = {
                    points:[],
                    status:0,
                    distance:0
                }
            });
            function drawLineCircle() {
                circleCfg.distance = qq.maps.geometry.spherical.computeDistanceBetween(circleCfg.points[0],circleCfg.points[1]);
                radiusOverlay.setPath(circleCfg.points);
                circleOverlay.setCenter(circleCfg.points[0]);
                circleOverlay.setRadius(circleCfg.distance);
                radiusInfoLabel.setContent(Ext.langs.radius+': &nbsp;<span style="color:red;">'+parseFloat(circleCfg.distance).toFixed(2)+'m</span>');
                radiusInfoLabel.setPosition(
                    new qq.maps.LatLng((circleCfg.points[0].lat-0+circleCfg.points[1].lat)/2
                                        ,(circleCfg.points[0].lng-0+circleCfg.points[1].lng)/2)
                );
            }
        }
    },
    getMap : function(){
        return this.map;
    },
    getCenter : function(){
        return this.map.getCenter();
    },
    getCenterLatLng : function(){
        var ll = this.getCenter();
        return {lat: ll.getLat(), lng: getLng()};
    },
    checkLatLng : function() {
        var me = this;
        if(me.longitude<0.000001&&me.latitude<0.0000001) {
            //经纬度0，0 则改为北京天安门
            me.longitude = me.defaultLongitude;
            me.latitude = me.defaultLatitude;
        }
    },
    addMarkers : function(datas) {
        var me = this;
        if (Ext.isArray(datas)){
            for (var i = 0; i < datas.length; i++) {
                var _markerCfg = me.filterFieldsFn ? filterFieldsFn(datas[i]):datas[i];
                var mkr_point = new qq.maps.LatLng( _markerCfg.latitude, _markerCfg.longitude);
                this.addMarker(mkr_point,_markerCfg,false,false,false,false);
            }
        }
    },
    addMarker : function(point, attr,clear, center, listeners){
        var me = this;
        if (clear === true){
            // this.getMap().clearOverlays();
        }
        if (center === true) {
            // this.getMap().setCenter(point, this.zoomLevel);
            me.map.setCenter(center);
        }

        var mark = new qq.maps.Marker({
            position: point,
            map: me.map
        });
        /*
        if (typeof listeners === 'object'){
            for (evt in listeners) {
                GEvent.bind(mark, evt, this, listeners[evt]);
            }
        }
        */
        if(attr) {
            mark.id = attr.id;
        }
        me.markers.push(mark);
        // this.getMap().addOverlay(mark);
        if(attr) {
            this.setMarkerPopUp(mark,attr);
        }
        return mark;
    },
    setMarkerPopUp:function(marker,attr) {
        var me = this;
        // marker.addEventListener('click',me.markerClickAction? me.markerClickAction:function() {
        //     var arr = ["'"+me.fieldsTpl+"'"].concat(me.fields);
        //     var params = eval('String.format('+arr.join(',')+')');          
        //     var infoWindow = new BMap.InfoWindow(params);  // 创建信息窗口对象
        //     marker.openInfoWindow(infoWindow);
        // });
        qq.maps.event.addListener(marker, 'click', function() {
            info.open(); 
            var arr = ["'"+me.fieldsTpl+"'"].concat(me.fields);
            var params = eval('String.format('+arr.join(',')+')');   
            info.setContent(params);
            info.setPosition(center); 
        });
    },
    updateMarkers:function(){
        var me = this;
        if(me.map.getBounds()) {
            me._updateMarkers();
        } else {
            qq.maps.event.addListener(me.map, 'bounds_changed', function() {
                me._updateMarkers();
            });
        }
        
    },
    _updateMarkers:function(){
        var me = this;
        var bounds = me.map.getBounds();
            var swPoint = bounds.getSouthWest();
            var enPoint = bounds.getNorthEast();
            var params = Ext.applyIf(
                            {left_longitude:swPoint.getLng(),left_latitude:swPoint.getLat(),
                            right_longitude:enPoint.getLng(),right_latitude:enPoint.getLat()},
                        me.params);
            ZM.ajax({
                url:me.url,
                params:params,
                success:function(res) {
                    //me.getMap().clearOverlays(); //清除所有的markers先,这里应该只清除不需要的再对，然后再去添加需要的
                    var datas = me.filterArray(me.markers,res.items);
                    me.markers = res.items;
                    me.removeMarkers(datas.deletes);
                    me.addMarkers(datas.adds);
                    me.afterDataLoad(me,res); //提供外部处理形式
                    me.getEl().unmask();
                }
            });
    },
    filterArray:function (oldArr,newArr){
        var oArr=oldArr.concat(), nArr = newArr.concat(), deletes = [], adds = [];
        for(var o=0; o<oArr.length; o++){
            for(var n=0; n<nArr.length; n++){
                if(oArr[o]==null||nArr[n]==null)
                    continue;
                if(oArr[o].id==nArr[n].id){
                    oArr[o]=null;
                    nArr[n]=null;
                    break; 
                }                       
            }
            if(oArr[o])
                deletes.push(oArr[o]);
        }
        for(var n=0; n<nArr.length; n++){
            if(nArr[n])
                adds.push(nArr[n]);
        }
        return {deletes:deletes, adds:adds};
    },
    removeMarkers:function(deletes) {
        // var me = this;
        // var overlays = me.map.getOverlays();        
        // for(var i = 0 ; i < overlays.length; i++) {
        //     for(var d=0; d<deletes.length; d++){
        //         if(overlays[i].id==deletes[d].id){
        //             me.map.removeOverlay(overlays[i]);
        //         }
        //     }           
        // }
        if (deletes.length > 0) {
            for (var i = 0 ; i < deletes.length ; i++) {
                deletes[i].setMap(null);
            }
        }
    },
    setCurLocation:function() {
        var me = this;
        if(!me.gc) {
            me.gc = new qq.maps.Geocoder({
                complete : function(rs){
                    console.log(rs);
                    me.curLocation = rs.addressComponents;
                    me.curLocation.address = rs.address;
                    me.afterLoaction && me.afterLoaction(me,rs);
                }
            });
        }
        me.gc.getAddress(new qq.maps.LatLng(me.latitude,me.longitude));     
    },
    getCurLocation:function() {
        return this.curLocation;
    }
});

/*add move column for move grid column(first,last,pre,next)*/
Ext.grid.MoveColumn = Ext.extend(Ext.grid.Column, {

    constructor: function(cfg){
        var me = this;
        me.renderer = function(val,m,r) {
            var str = '';
            if(!Ext.isDefined(me.canSortFn) || me.canSortFn(val,m,r)) {
                str += '<a href="#" id="_'+r.id+'" class="moveFirst" title="moveFirst" ></a>';
                str += '<a href="#" id="_'+r.id+'" class="movePrevious" title="movePrevious" ></a>';
                str += '<a href="#" id="_'+r.id+'" class="moveNext" title="moveNext" ></a>';
                str += '<a href="#" id="_'+r.id+'" class="moveLast" title="moveLast" ></a>';
            }
            return str;
        }
        Ext.grid.MoveColumn.superclass.constructor.call(this, cfg);
    }
});
Ext.grid.Column.types.movecolumn = Ext.grid.MoveColumn;

/*add sort column for eidtor grid column(url,dataId)*/
Ext.grid.SortColumn = Ext.extend(Ext.grid.Column, {

    constructor: function(cfg){
        var me = this;
        Ext.applyIf(cfg,{
            dataId: 'id',
            editor: new Ext.form.TriggerField({
                triggerClass:'x-form-save-trigger',
                onTriggerClick: function(e,el,v) {
                    var v = this.getValue();
                    var id = me.grid.store.getAt(me.grid.rowNumber).get(me.dataId);
                    var params = me.params||{};
                    params[me.dataIndex] = v;
                    params[me.dataId] = id;
                    ZM.ajax({
                        url: me.url,
                        params:params,
                        success:function(r){        
                            ZM.bo.msg('成功',r.detail);
                            me.grid.store.reload();
                        }
                    });
                }
            })
        });
        if(String(cfg.id).indexOf('editor') == -1) {
            cfg.id = 'editor0';
        }
        Ext.grid.SortColumn.superclass.constructor.call(this, cfg);
    }
});
Ext.grid.Column.types.sortcolumn = Ext.grid.SortColumn;

//树 
ZM.TreePanel = function(config) {

    var config = config || {};
    var tree = this;
    var me = this;
    
    if(!Ext.isDefined(config.preloadChildren)) {
        config.preloadChildren = true;
    }
    
    config.preloadChildren == Ext.isDefined(config.preloadChildren) ? config.preloadChildren :true;
    Ext.applyIf(config,{
        useArrows: false,
        autoScroll: true,
        animate: true,
        enableDD: true,
        autoScroll:true,
        border: false,
        rootVisible: false,
        name:'tree',
        paramName:'text',
        root:new Ext.tree.AsyncTreeNode({
            expanded: true,
            nodeType:'async',
            id:'0'
        }),
        loader: new Ext.tree.TreeLoader({
            dataUrl:config.dataUrl||config.url||'cmsjsontree.json',
            dataRoot: config.dataRoot||'items',
            preloadChildren:config.preloadChildren,
            baseParams:config.baseParams
        })
    });
    ZM.TreePanel.superclass.constructor.call(this, config);
    
    this.loader.on({
        beforeload:function(l,n) {
            n.getOwnerTree().el.mask(Ext.langs.loading,'x-mask-loading');
        },
        load:function(l,n) {
            n.getOwnerTree().el.unmask();
        },
        loadexception:function(l,n) {
            Ext.Msg.alert(Ext.langs.error,Ext.langs.dataLoadingError);
        },
        scope:this.loader
    });
    this.on('afterrender',function(){
        var frm = me.findParentByType('formpanel');
        if(frm) {
            frm.params = frm.params || {};
            tree.on('checkchange',function(node,checked) {
                // if(isCheckChangeNode) return;
                
                if(!node.childrenRendered){
                    node.renderChildren();
                }

                function toggleCheck(node) {
                    if(!node.hasChildNodes()) return;
                    node.eachChild(function(n){
                        var checked = node.ui.checkbox.checked;
                        toggleNodeCheck(n,checked)
                        if(!n.childrenRendered){
                            n.renderChildren();
                        }
                        toggleCheck(n);
                    });
                }
                
                function toggleNodeCheck(n,checked) {
                    if(!n.ui.checkbox) return;
                    n.ui.checkbox.checked = checked;
                    // fix for IE6
                    n.ui.checkbox.defaultChecked = checked;
                    n.attributes.checked = checked;
                }
                
                toggleCheck(node);
                var n = node.parentNode;
                while(n) {
                    var ischecked = true;
                    n.eachChild(function(cn){
                        if(!cn.ui.isChecked()) {
                            ischecked = false;
                        }
                    });
                    toggleNodeCheck(n,ischecked);
                    n = n.parentNode;
                }
                
                ZM.clearArrayParam(frm.params,config.name);
                var rows = tree.getChecked();       
                var ni = 0;
                Ext.each(rows,function(r,i) {
                    var v = r.attributes[config.paramName];
                    if(Ext.isDefined(v)) {
                        frm.params[config.name + '['+(ni++)+']'] = r.attributes[config.paramName];
                    }
                });
            });
        }
    });
    
    
};
Ext.extend(ZM.TreePanel, Ext.tree.TreePanel);
Ext.reg('ys-treepanel', ZM.TreePanel);

Ext.override(Ext.tree.TreeLoader, {
    processResponse : function(response, node, callback, scope){
        var json = response.responseText;
        try {
            var o = (response.responseData || Ext.decode(json));
            if(this.dataRoot) oi = eval('(o.'+this.dataRoot+')');
            this.store = o;
            node.beginUpdate();
            for(var i = 0, len = oi.length; i < len; i++){
                var n = this.createNode(oi[i]);
                if(n){
                    node.appendChild(n);
                    if(this.preloadChildren) {
                        this.doPreload(n);
                    }
                }
            }
            node.endUpdate();
            this.runCallback(callback, scope || node, [node]);
        }catch(e){
            this.handleFailure(response);
        }
    }
});

/*
// delete timeout exit;
// klj 2013-11-08
Ext.override(Ext.data.Connection, {
    handleResponse : function(response){
        this.transId = false;
        var options = response.argument.options;
        response.argument = options ? options.argument : null;
        this.fireEvent('requestcomplete', this, response, options);
        if(options.success){
            options.success.call(options.scope, response, options);
        }
        if(options.callback){
            options.callback.call(options.scope, options, true, response);
        }

        var res = Ext.decode(response.responseText);
        if(res.addon.code == 401) {
            location.reload();
        }
    },

    handleFailure : function(response, e){
        this.transId = false;
        var options = response.argument.options;
        response.argument = options ? options.argument : null;
        this.fireEvent('requestexception', this, response, options, e);
        if(options.failure){
            options.failure.call(options.scope, response, options);
        }
        if(options.callback){
            options.callback.call(options.scope, options, false, response);
        }

        var res = Ext.decode(response.responseText);
        if(res && res.addon.code == 401) {
            location.reload();
        }
    }
});
*/
/*fix datefield ie6 bug*/
Ext.override(Ext.menu.DateMenu,{
    minWidth:182
});

Ext.override(Ext.form.NumberField,{
    decimalPrecision:5
});

Ext.override(Ext.data.Connection,{
    timeout:180000
});
/*gridPanle action*/
Ext.rd = function(text,title,r,permission,cls,style){
    if(!Ext.isDefined(permission)||Ext.permission[permission.toLowerCase()]){
        return '<a href="#" id="_'+r.id+'" title="'+title+'" '+(cls?(' class="'+cls+'" '):'')+ (style?(' style="'+style+'" '):'')+' >['+text+']</a>';
    }
    return '';
}
Ext.pm = function(permission) {
    return Ext.permission[permission.toLowerCase()];
}

/*textarea tab key */
ZM.tabKey = function(config){
    Ext.apply(this, config);
    ZM.tabKey.superclass.constructor.call(this);
};
Ext.extend(ZM.tabKey, Ext.util.Observable, {
    init : function(field){
        field.on('afterrender', function(f){
            f.on('specialkey',function(f,e) {
                var key = e.getKey();
                if (key == e.TAB) {
                    ZM.insertAtCursor(f.el.dom,'\t');
                    e.stopEvent();
                }else if (e.ctrlKey&&(key==100||key==112||key==104||key==119)){
                    ZM.wrapTag(f.el.dom,key);
                    e.stopEvent();
                }
            });
        }, this, {buffer:250});
    }
});

//MonthPickerPlugin.js文件,年月选择的关键代码
Ext.ux.MonthPickerPlugin = function() { 
    var picker; 
    var oldDateDefaults; 

    this.init = function(pk) { 
        picker = pk; 
        picker.onTriggerClick = picker.onTriggerClick.createSequence(onClick); 
        picker.getValue = picker.getValue.createInterceptor(setDefaultMonthDay).createSequence(restoreDefaultMonthDay); 
        picker.beforeBlur = picker.beforeBlur.createInterceptor(setDefaultMonthDay).createSequence(restoreDefaultMonthDay); 
    }; 

    function setDefaultMonthDay() { 
        oldDateDefaults = Date.defaults.d; 
        Date.defaults.d = 1; 
        return true; 
    } 

    function restoreDefaultMonthDay(ret) { 
        Date.defaults.d = oldDateDefaults; 
        return ret; 
    } 

    function onClick(e, el, opt) { 
        var p = picker.menu.picker; 
        p.activeDate = p.activeDate.getFirstDateOfMonth(); 
        if (p.value) { 
            p.value = p.value.getFirstDateOfMonth(); 
        } 

        p.showMonthPicker(); 
         
        if (!p.disabled) { 
            p.monthPicker.stopFx(); 
            p.monthPicker.show(); 
   // if you want to click,you can the dblclick event change click
            p.mun(p.monthPicker, 'click', p.onMonthClick, p); 
            p.mun(p.monthPicker, 'click', p.onMonthDblClick, p); 
            p.onMonthClick = p.onMonthClick.createSequence(pickerClick); 
            p.onMonthDblClick = p.onMonthDblClick.createSequence(pickerDblclick); 
            p.mon(p.monthPicker, 'click', p.onMonthClick, p); 
            p.mon(p.monthPicker, 'click', p.onMonthDblClick, p); 
        } 
    } 

    function pickerClick(e, t) { 
        var el = new Ext.Element(t); 
        if (el.is('button.x-date-mp-cancel')) { 
            picker.menu.hide(); 
        } else if(el.is('button.x-date-mp-ok')) { 
            var p = picker.menu.picker; 
            p.setValue(p.activeDate); 
            p.fireEvent('select', p, p.value); 
        } 
    } 

    function pickerDblclick(e, t) { 
        var el = new Ext.Element(t); 
        if (el.parent() 
            && (el.parent().is('td.x-date-mp-month') 
            || el.parent().is('td.x-date-mp-year'))) { 

            var p = picker.menu.picker; 
            p.setValue(p.activeDate); 
            p.fireEvent('select', p, p.value); 
        } 
    } 
}; 

Ext.preg('monthPickerPlugin', Ext.ux.MonthPickerPlugin);  

/*!
 * Ext JS Library 3.4.0
 * Copyright(c) 2006-2011 Sencha Inc.
 * licensing@sencha.com
 * http://www.sencha.com/license
 */
Ext.ns('Ext.ux.form');

/**
 * @class Ext.ux.form.FileUploadField
 * @extends Ext.form.TextField
 * Creates a file upload field.
 * @xtype fileuploadfield
 */
Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField,  {
    /**
     * @cfg {String} buttonText The button text to display on the upload button (defaults to
     * 'Browse...').  Note that if you supply a value for {@link #buttonCfg}, the buttonCfg.text
     * value will be used instead if available.
     */
    buttonText: 'Browse...',
    /**
     * @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible
     * text field (defaults to false).  If true, all inherited TextField members will still be available.
     */
    buttonOnly: false,
    /**
     * @cfg {Number} buttonOffset The number of pixels of space reserved between the button and the text field
     * (defaults to 3).  Note that this only applies if {@link #buttonOnly} = false.
     */
    buttonOffset: 3,
    /**
     * @cfg {Object} buttonCfg A standard {@link Ext.Button} config object.
     */

    // private
    readOnly: true,

    /**
     * @hide
     * @method autoSize
     */
    autoSize: Ext.emptyFn,

    /**
     * array[][] length:3
     * 0->base64(all)
     * 1->base64(mime)
     * 2->base64(image)
     * @format value(base64)
     */
    fmValue:[],
    /**
     * @format value(base64)
     */
    fileType:'',

    // private
    initComponent: function(){
        Ext.ux.form.FileUploadField.superclass.initComponent.call(this);

        this.addEvents(
            /**
             * @event fileselected
             * Fires when the underlying file input field's value has changed from the user
             * selecting a new file from the system file selection dialog.
             * @param {Ext.ux.form.FileUploadField} this
             * @param {String} value The file value returned by the underlying file input field
             */
            'fileselected'
        );
    },

    // private
    onRender : function(ct, position){
        Ext.ux.form.FileUploadField.superclass.onRender.call(this, ct, position);

        var me = this;
        this.wrap = this.el.wrap({cls:'x-form-field-wrap x-form-file-wrap'});
        this.el.addClass('x-form-file-text');
        this.el.dom.removeAttribute('name');
        this.createFileInput();

        var btnCfg = Ext.applyIf(this.buttonCfg || {}, {
            text: this.buttonText
        });
        this.button = new Ext.Button(Ext.apply(btnCfg, {
            renderTo: this.wrap,
            cls: 'x-form-file-btn' + (btnCfg.iconCls ? ' x-btn-icon' : '') + ' btn-show'
        }));

        if(this.buttonOnly){
            this.el.hide();
            this.wrap.setWidth(this.button.getEl().getWidth());
        }

        this.bindListeners();
        this.resizeEl = this.positionEl = this.wrap;

        if(!me.disabled) {
            this.tip = new Ext.ToolTip({
                target: this.el,
                trackMouse: false,
                html:'',
                listeners:{
                    beforeshow:function(tip) {
                        var html = (me.fmValue.length>0?('<img src='+me.fmValue[0][0]+' width="100px;"/>'):Ext.langs.chooseFile);
                        if(tip.body) {
                            tip.body.update(html);
                        } else {
                            tip.html = html;
                        }
                    }
                }
            });
        }
    },

    bindListeners: function(){
        var me = this;
        this.fileInput.on({
            scope: this,
            mouseenter: function() {
                this.button.addClass(['x-btn-over','x-btn-focus'])
            },
            mouseleave: function(){
                this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click'])
            },
            mousedown: function(){
                this.button.addClass('x-btn-click');
                /*if (typeof(window.FileReader) == 'undefined') {
                 alert('Browser does not support HTML5 file uploads!');
                 }*/
            },
            mouseup: function(){
                this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click'])
            },
            change: function(){
                var me = this;
                var formPanel = me.findParentByType('formpanel');
                if(formPanel) {
                    formPanel.params = formPanel.params||{};
                }
                me.removeFileParams();
                var params = {};
                for(var i= 0,len = this.fileInput.dom.files.length; i < len;i++) {
                    var file = this.fileInput.dom.files[i];
                    if(file) {
                        if(me.fileType) {
                            var mimetype = this.fileType.replace(/\*/g,'\\w+');
                            mimetype = mimetype.replace(/\//g,'\\/');
                            var reg = new RegExp(mimetype);
                            if(!reg.test(file.type)) {
                                Ext.Msg.alert(Ext.langs.error,Ext.langs.wrongFileFormat);
                                return ;
                            }
                        }
                        (function(index,f){
                            var reader = new FileReader();
                            reader.readAsDataURL(file);
                            reader.onload = function(e) {
                                var imageData = this.result.toString();
                                var fname = me.getName()+(me.multiple?('['+index+']'):'');
                                me.fmValue.push(fname);
                                params[fname+'[name]'] = f.name;
                                params[fname+'[data]'] = imageData.split(',').pop();
                                params[fname+'[suffix]'] = file.name.indexOf('.')>=0?file.name.split('.').pop():'';
                                params[fname+'[type]'] = f.type;
                                if(index == (len-1)) {
                                    if(formPanel) {
                                        Ext.apply(formPanel.params,params);
                                    }
                                    me.setValue(me.fmValue.join(','));
                                    me.fireEvent('fileselected', me, me.fmValue,params);
                                }
                            }
                        })(i,file);
                    }
                }
            }
        });
    },

    createFileInput : function() {
        var opts = {
            id: this.getFileInputId(),
            name: this.name||this.getId(),
            cls: 'x-form-file',
            tag: 'input',
            type: 'file',
            size: 1
        };
        this.fileType && (opts.accept = this.fileType);
        this.multiple && (opts.multiple='multiple');
        this.fileInput = this.wrap.createChild(opts);
    },

    removeFileParams:function() {
        var me = this;
        var formPanel = me.findParentByType('formpanel');
        if(me.fmValue&&formPanel&&formPanel.params) {
            Ext.each(me.fmValue,function(val,i) {
                Ext.each(['name','data','type','suffix'],function(vval,vi) {
                    delete formPanel.params[val][vval];
                });
            });
        }
        me.fmValue = [];
    },

    reset : function(){
        if (this.rendered) {
            this.fileInput.remove();
            this.createFileInput();
            this.bindListeners();
        }
        Ext.ux.form.FileUploadField.superclass.reset.call(this);
    },

    // private
    getFileInputId: function(){
        return this.id + '-file';
    },

    // private
    onResize : function(w, h){
        Ext.ux.form.FileUploadField.superclass.onResize.call(this, w, h);

        this.wrap.setWidth(w);

        if(!this.buttonOnly){
            var w = this.wrap.getWidth() - this.button.getEl().getWidth() - this.buttonOffset;
            this.el.setWidth(w);
        }
    },

    // private
    onDestroy: function(){
        Ext.ux.form.FileUploadField.superclass.onDestroy.call(this);
        Ext.destroy(this.fileInput, this.button, this.wrap);
    },

    onDisable: function(){
        Ext.ux.form.FileUploadField.superclass.onDisable.call(this);
        this.doDisable(true);
    },

    onEnable: function(){
        Ext.ux.form.FileUploadField.superclass.onEnable.call(this);
        this.doDisable(false);
    },

    // private
    doDisable: function(disabled){
        this.fileInput.dom.disabled = disabled;
        this.button.setDisabled(disabled);
    },


    // private
    preFocus : Ext.emptyFn,

    // private
    alignErrorIcon : function(){
        this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
    }

});

Ext.reg('fileuploadfield', Ext.ux.form.FileUploadField);

// backwards compat
Ext.form.FileUploadField = Ext.ux.form.FileUploadField;